PartMC  2.6.1
integer_rmap.F90
Go to the documentation of this file.
1 ! Copyright (C) 2011-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 pmc_integer_rmap module.
7 
8 !> The integer_rmap_t structure and assocated subroutines.
10 
12  use pmc_util
13  use pmc_mpi
14 
15  !> A map from integers to integers, together with its multi-valued
16  !> inverse.
17  !!
18  !! The forward map takes integer \f$i\f$ in the domain
19  !! 1,...,n_domain to an integer \f$j\f$ in the range
20  !! 1,...,n_range. This is stored with <tt>j =
21  !! integer_rmap%%forward%%entry(i)</tt>. This map will generally not be
22  !! one-to-one or onto.
23  !!
24  !! The inverse map is multi-valued, with
25  !! <tt>integer_rmap%%inverse(j)</tt> containing all the inverses of
26  !! \f$j\f$. The entries in the inverse map are given by
27  !! <tt>inverse_rmap%%index</tt>. The relationships between
28  !! the forward and reverse maps are as follows.
29  !!
30  !! Given \f$i\f$, let:
31  !! <pre>
32  !! j = integer_rmap%%forward%%entry(i)
33  !! k = integer_rmap%%index%%entry(i)
34  !! </pre>
35  !! Then:
36  !! <pre>
37  !! integer_rmap%%inverse(j)%%entry(k) == i
38  !! </pre>
39  !!
40  !! Alternatively, given \f$j\f$ and \f$k\f$, let:
41  !! <pre>
42  !! i = integer_rmap%%inverse(j)%%entry(k)
43  !! </pre>
44  !! Then:
45  !! <pre>
46  !! integer_rmap%%forward%%entry(i) == j
47  !! integer_rmap%%index%%entry(i) == k
48  !! </pre>
50  !> Forward map (single valued).
51  type(integer_varray_t) :: forward
52  !> Inverse map (multi-valued).
53  type(integer_varray_t), allocatable :: inverse(:)
54  !> Forward map to inverse map entries (single valued).
55  type(integer_varray_t) :: index
56  end type integer_rmap_t
57 
58 contains
59 
60 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
61 
62  !> Sets the maximum range of the forward map.
63  elemental subroutine integer_rmap_set_range(integer_rmap, n_range)
64 
65  !> Structure to initialize.
66  type(integer_rmap_t), intent(out) :: integer_rmap
67  !> Size of range space.
68  integer, intent(in) :: n_range
69 
70  if (allocated(integer_rmap%inverse)) then
71  deallocate(integer_rmap%inverse)
72  end if
73  allocate(integer_rmap%inverse(n_range))
74 
75  end subroutine integer_rmap_set_range
76 
77 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
78 
79  !> Resets an integer_rmap to have no mappings.
80  elemental subroutine integer_rmap_zero(integer_rmap)
81 
82  !> Structure to zero.
83  type(integer_rmap_t), intent(inout) :: integer_rmap
84 
85  call integer_varray_zero(integer_rmap%forward)
86  if (allocated(integer_rmap%inverse)) then
87  call integer_varray_zero(integer_rmap%inverse)
88  end if
89  call integer_varray_zero(integer_rmap%index)
90 
91  end subroutine integer_rmap_zero
92 
93 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
94 
95  !> Set the map value of the next free domain value to \c i_range.
96  subroutine integer_rmap_append(integer_rmap, i_range)
97 
98  !> Map to append to.
99  type(integer_rmap_t), intent(inout) :: integer_rmap
100  !> Range value.
101  integer, intent(in) :: i_range
102 
103  call assert(200002696, allocated(integer_rmap%inverse))
104  call assert(549740445, i_range >= 1)
105  call assert(145872613, i_range <= size(integer_rmap%inverse))
106 
107  ! grow map by one element
108  call integer_varray_append(integer_rmap%forward, i_range)
109  call integer_varray_append(integer_rmap%inverse(i_range), &
110  integer_varray_n_entry(integer_rmap%forward))
111  call integer_varray_append(integer_rmap%index, &
112  integer_varray_n_entry(integer_rmap%inverse(i_range)))
113 
114  end subroutine integer_rmap_append
115 
116 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
117 
118  !> Change the map value of \c i_domain to \c i_range.
119  subroutine integer_rmap_change(integer_rmap, i_domain, i_range)
120 
121  !> Map to change.
122  type(integer_rmap_t), intent(inout) :: integer_rmap
123  !> Domain value.
124  integer, intent(in) :: i_domain
125  !> Range value.
126  integer, intent(in) :: i_range
127 
128  integer :: i_range_old, i_index_old, i_domain_shifted
129 
130  call assert(483243151, allocated(integer_rmap%inverse))
131  call assert(709581778, i_domain >= 1)
132  call assert(494892311, &
133  i_domain <= integer_varray_n_entry(integer_rmap%forward))
134 
135  call assert(590911054, i_range >= 1)
136  call assert(859774512, i_range <= size(integer_rmap%inverse))
137 
138  i_range_old = integer_rmap%forward%entry(i_domain)
139  if (i_range_old == i_range) return
140  i_index_old = integer_rmap%index%entry(i_domain)
141 
142  ! remove the old inverse map
143  call integer_varray_remove_entry(integer_rmap%inverse(i_range_old), &
144  i_index_old)
145  if (i_index_old &
146  <= integer_varray_n_entry(integer_rmap%inverse(i_range_old))) then
147  ! the removed entry wasn't the last one, so the last entry
148  ! was moved and needs fixing
149  i_domain_shifted = integer_rmap%inverse(i_range_old)%entry(i_index_old)
150  integer_rmap%index%entry(i_domain_shifted) = i_index_old
151  end if
152 
153  ! set the new map and inverse
154  integer_rmap%forward%entry(i_domain) = i_range
155  call integer_varray_append(integer_rmap%inverse(i_range), i_domain)
156  integer_rmap%index%entry(i_domain) &
157  = integer_varray_n_entry(integer_rmap%inverse(i_range))
158 
159  end subroutine integer_rmap_change
160 
161 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
162 
163  !> Replace the map at the given \c i_domain with the map value of
164  !> the last entry, and delete the last entry.
165  subroutine integer_rmap_remove(integer_rmap, i_domain)
166 
167  !> Map to remove from.
168  type(integer_rmap_t), intent(inout) :: integer_rmap
169  !> Domain value to replace.
170  integer, intent(in) :: i_domain
171 
172  integer :: i_range_old, i_index_old, i_domain_shifted, i_range_fix
173  integer :: i_index_fix, i_domain_fix
174 
175  call assert(790455753, allocated(integer_rmap%inverse))
176  call assert(745161821, i_domain >= 1)
177  call assert(143043782, i_domain &
178  <= integer_varray_n_entry(integer_rmap%forward))
179 
180  ! Deleting particles shifts the end particles into the empty slots
181  ! in the aero_particle_array and the aero_sorted forward and
182  ! reverse indexes. All must be fixed in the right order to
183  ! maintain consistency.
184 
185  i_range_old = integer_rmap%forward%entry(i_domain)
186  i_index_old = integer_rmap%index%entry(i_domain)
187 
188  ! old loc of shifted value
189  i_domain_shifted = integer_varray_n_entry(integer_rmap%forward)
190  if (i_domain_shifted /= i_domain) then
191  i_range_fix = integer_rmap%forward%entry(i_domain_shifted)
192  i_index_fix = integer_rmap%index%entry(i_domain_shifted)
193  integer_rmap%inverse(i_range_fix)%entry(i_index_fix) = i_domain
194  end if
195 
196  ! remove the particle from the forward map (with the side effect
197  ! of fixing the forward map for the shifted value)
198  call integer_varray_remove_entry(integer_rmap%forward, i_domain)
199  call integer_varray_remove_entry(integer_rmap%index, i_domain)
200 
201  ! remove the inverse map
202  i_index_fix = integer_varray_n_entry(integer_rmap%inverse(i_range_old))
203  i_domain_fix = integer_rmap%inverse(i_range_old)%entry(i_index_fix)
204  call integer_varray_remove_entry(integer_rmap%inverse(i_range_old), &
205  i_index_old)
206 
207  if (i_index_fix /= i_index_old) then
208  ! fix index map
209  integer_rmap%index%entry(i_domain_fix) = i_index_old
210  end if
211 
212  end subroutine integer_rmap_remove
213 
214 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
215 
216  !> Check that the data is consistent.
217  subroutine integer_rmap_check(integer_rmap, name, n_domain, n_range, &
218  continue_on_error)
219 
220  !> Structure to check.
221  type(integer_rmap_t) :: integer_rmap
222  !> Check name.
223  character(len=*), intent(in) :: name
224  !> Number of domain items.
225  integer, intent(in) :: n_domain
226  !> Number of image items.
227  integer, intent(in) :: n_range
228  !> Whether to continue despite error.
229  logical, intent(in) :: continue_on_error
230 
231  integer :: i_domain, i_range, i_index
232 
233  if (.not. allocated(integer_rmap%inverse)) then
234  return
235  end if
236 
237  if ((n_domain /= integer_varray_n_entry(integer_rmap%forward)) &
238  .or. (n_domain /= integer_varray_n_entry(integer_rmap%index)) &
239  .or. (n_range /= size(integer_rmap%inverse))) then
240  write(0,*) 'ERROR integer_rmap A:', name
241  write(0,*) 'n_domain', n_domain
242  write(0,*) 'n_range', n_range
243  write(0,*) 'integer_varray_n_entry(integer_rmap%forward)', &
244  integer_varray_n_entry(integer_rmap%forward)
245  write(0,*) 'integer_varray_n_entry(integer_rmap%index)', &
246  integer_varray_n_entry(integer_rmap%index)
247  write(0,*) 'size(integer_rmap%inverse)', size(integer_rmap%inverse)
248  call assert(973643016, continue_on_error)
249  end if
250 
251  do i_domain = 1,n_domain
252  i_range = integer_rmap%forward%entry(i_domain)
253  if ((i_range < 1) .or. (i_range > n_range)) then
254  write(0,*) 'ERROR integer_rmap B:', name
255  write(0,*) 'i_domain', i_domain
256  write(0,*) 'i_range', i_range
257  write(0,*) 'n_range', n_range
258  call assert(798857945, continue_on_error)
259  end if
260 
261  i_index = integer_rmap%index%entry(i_domain)
262  if ((i_index < 1) &
263  .or. (i_index &
264  > integer_varray_n_entry(integer_rmap%inverse(i_range)))) then
265  write(0,*) 'ERROR integer_rmap C:', name
266  write(0,*) 'i_domain', i_domain
267  write(0,*) 'i_range', i_range
268  write(0,*) 'i_index', i_index
269  write(0,*) 'integer_varray_n_entry(integer_rmap%inverse(i_range))', &
270  integer_varray_n_entry(integer_rmap%inverse(i_range))
271  call assert(823748734, continue_on_error)
272  end if
273  if (i_domain /= integer_rmap%inverse(i_range)%entry(i_index)) then
274  write(0,*) 'ERROR integer_rmap D:', name
275  write(0,*) 'i_domain', i_domain
276  write(0,*) 'i_range', i_range
277  write(0,*) 'i_index', i_index
278  write(0,*) 'integer_rmap%inverse(i_range)%entry(i_index)', &
279  integer_rmap%inverse(i_range)%entry(i_index)
280  call assert(735205557, continue_on_error)
281  end if
282  end do
283 
284  do i_range = 1,n_range
285  do i_index = 1,integer_varray_n_entry(integer_rmap%inverse(i_range))
286  i_domain = integer_rmap%inverse(i_range)%entry(i_index)
287  if ((i_domain < 1) .or. (i_domain > n_domain)) then
288  write(0,*) 'ERROR integer_rmap E:', name
289  write(0,*) 'i_range', i_range
290  write(0,*) 'i_index', i_index
291  write(0,*) 'i_domain', i_domain
292  write(0,*) 'n_domain', n_domain
293  call assert(502643520, continue_on_error)
294  end if
295  if ((i_range /= integer_rmap%forward%entry(i_domain)) &
296  .or. (i_index /= integer_rmap%index%entry(i_domain))) then
297  write(0,*) 'ERROR integer_rmap F:', name
298  write(0,*) 'i_domain', i_domain
299  write(0,*) 'i_range', i_range
300  write(0,*) 'integer_rmap%forward%entry(i_domain)', &
301  integer_rmap%forward%entry(i_domain)
302  write(0,*) 'i_index', i_index
303  write(0,*) 'integer_rmap%index%entry(i_domain)', &
304  integer_rmap%index%entry(i_domain)
305  call assert(544747928, continue_on_error)
306  end if
307  end do
308  end do
309 
310  end subroutine integer_rmap_check
311 
312 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
313 
314  !> Determines the number of bytes required to pack the given value.
315  integer function pmc_mpi_pack_size_integer_rmap(val)
316 
317  !> Value to pack.
318  type(integer_rmap_t), intent(in) :: val
319 
320  integer :: i, total_size
321  logical :: is_allocated
322 
323  total_size = 0
324  is_allocated = allocated(val%inverse)
325  total_size = total_size + pmc_mpi_pack_size_logical(is_allocated)
326  if (is_allocated) then
327  total_size = total_size + pmc_mpi_pack_size_integer(size(val%inverse))
328  do i = 1,size(val%inverse)
329  total_size = total_size &
330  + pmc_mpi_pack_size_integer_varray(val%inverse(i))
331  end do
332  end if
333  total_size = total_size + pmc_mpi_pack_size_integer_varray(val%forward)
334  total_size = total_size + pmc_mpi_pack_size_integer_varray(val%index)
335  pmc_mpi_pack_size_integer_rmap = total_size
336 
337  end function pmc_mpi_pack_size_integer_rmap
338 
339 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
340 
341  !> Packs the given value into the buffer, advancing position.
342  subroutine pmc_mpi_pack_integer_rmap(buffer, position, val)
343 
344  !> Memory buffer.
345  character, intent(inout) :: buffer(:)
346  !> Current buffer position.
347  integer, intent(inout) :: position
348  !> Value to pack.
349  type(integer_rmap_t), intent(in) :: val
350 
351 #ifdef PMC_USE_MPI
352  integer :: prev_position, i
353  logical :: is_allocated
354 
355  prev_position = position
356  is_allocated = allocated(val%inverse)
357  call pmc_mpi_pack_logical(buffer, position, is_allocated)
358  if (is_allocated) then
359  call pmc_mpi_pack_integer(buffer, position, size(val%inverse))
360  do i = 1,size(val%inverse)
361  call pmc_mpi_pack_integer_varray(buffer, position, val%inverse(i))
362  end do
363  end if
364  call pmc_mpi_pack_integer_varray(buffer, position, val%forward)
365  call pmc_mpi_pack_integer_varray(buffer, position, val%index)
366  call assert(533568488, &
367  position - prev_position <= pmc_mpi_pack_size_integer_rmap(val))
368 #endif
369 
370  end subroutine pmc_mpi_pack_integer_rmap
371 
372 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
373 
374  !> Unpacks the given value from the buffer, advancing position.
375  subroutine pmc_mpi_unpack_integer_rmap(buffer, position, val)
376 
377  !> Memory buffer.
378  character, intent(inout) :: buffer(:)
379  !> Current buffer position.
380  integer, intent(inout) :: position
381  !> Value to pack.
382  type(integer_rmap_t), intent(inout) :: val
383 
384 #ifdef PMC_USE_MPI
385  integer :: prev_position, i, n
386  logical :: is_allocated
387 
388  prev_position = position
389  call pmc_mpi_unpack_logical(buffer, position, is_allocated)
390  if (is_allocated) then
391  call pmc_mpi_unpack_integer(buffer, position, n)
392  call integer_rmap_set_range(val, n)
393  do i = 1,size(val%inverse)
394  call pmc_mpi_unpack_integer_varray(buffer, position, val%inverse(i))
395  end do
396  else
397  if (allocated(val%inverse)) then
398  deallocate(val%inverse)
399  end if
400  end if
401  call pmc_mpi_unpack_integer_varray(buffer, position, val%forward)
402  call pmc_mpi_unpack_integer_varray(buffer, position, val%index)
403  call assert(663161025, &
404  position - prev_position <= pmc_mpi_pack_size_integer_rmap(val))
405 #endif
406 
407  end subroutine pmc_mpi_unpack_integer_rmap
408 
409 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
410 
411 end module pmc_integer_rmap
pmc_integer_rmap::integer_rmap_remove
subroutine integer_rmap_remove(integer_rmap, i_domain)
Replace the map at the given i_domain with the map value of the last entry, and delete the last entry...
Definition: integer_rmap.F90:166
pmc_integer_rmap::pmc_mpi_unpack_integer_rmap
subroutine pmc_mpi_unpack_integer_rmap(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: integer_rmap.F90:376
pmc_mpi
Wrapper functions for MPI.
Definition: mpi.F90:13
pmc_integer_varray::integer_varray_zero
elemental subroutine integer_varray_zero(integer_varray)
Resets an integer_varray to have zero entries.
Definition: integer_varray.F90:76
pmc_integer_rmap::integer_rmap_check
subroutine integer_rmap_check(integer_rmap, name, n_domain, n_range, continue_on_error)
Check that the data is consistent.
Definition: integer_rmap.F90:219
pmc_integer_rmap::integer_rmap_append
subroutine integer_rmap_append(integer_rmap, i_range)
Set the map value of the next free domain value to i_range.
Definition: integer_rmap.F90:97
pmc_integer_rmap::pmc_mpi_pack_integer_rmap
subroutine pmc_mpi_pack_integer_rmap(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: integer_rmap.F90:343
pmc_mpi::pmc_mpi_pack_logical
subroutine pmc_mpi_pack_logical(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:638
pmc_integer_rmap::pmc_mpi_pack_size_integer_rmap
integer function pmc_mpi_pack_size_integer_rmap(val)
Determines the number of bytes required to pack the given value.
Definition: integer_rmap.F90:316
pmc_util::assert
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
Definition: util.F90:103
pmc_integer_varray::pmc_mpi_pack_size_integer_varray
integer function pmc_mpi_pack_size_integer_varray(val)
Determines the number of bytes required to pack the given value.
Definition: integer_varray.F90:177
pmc_integer_rmap::integer_rmap_t
A map from integers to integers, together with its multi-valued inverse.
Definition: integer_rmap.F90:49
pmc_integer_varray::integer_varray_n_entry
elemental integer function integer_varray_n_entry(integer_varray)
Return the current number of entries.
Definition: integer_varray.F90:31
pmc_mpi::pmc_mpi_pack_size_logical
integer function pmc_mpi_pack_size_logical(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:407
pmc_integer_rmap
The integer_rmap_t structure and assocated subroutines.
Definition: integer_rmap.F90:9
pmc_integer_varray
The integer_varray_t structure and assocated subroutines.
Definition: integer_varray.F90:9
pmc_integer_varray::integer_varray_t
A variable-length 1D array of integers.
Definition: integer_varray.F90:18
pmc_integer_rmap::integer_rmap_change
subroutine integer_rmap_change(integer_rmap, i_domain, i_range)
Change the map value of i_domain to i_range.
Definition: integer_rmap.F90:120
pmc_integer_varray::integer_varray_remove_entry
subroutine integer_varray_remove_entry(integer_varray, index)
Removes the entry at the given index, repacking values to maintain contiguous data.
Definition: integer_varray.F90:152
pmc_integer_varray::pmc_mpi_pack_integer_varray
subroutine pmc_mpi_pack_integer_varray(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: integer_varray.F90:200
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_mpi::pmc_mpi_unpack_logical
subroutine pmc_mpi_unpack_logical(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:896
pmc_integer_varray::pmc_mpi_unpack_integer_varray
subroutine pmc_mpi_unpack_integer_varray(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: integer_varray.F90:230
pmc_util
Common utility subroutines.
Definition: util.F90:9
pmc_integer_varray::integer_varray_append
subroutine integer_varray_append(integer_varray, val)
Adds the given number to the end of the array.
Definition: integer_varray.F90:132
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_integer_rmap::integer_rmap_zero
elemental subroutine integer_rmap_zero(integer_rmap)
Resets an integer_rmap to have no mappings.
Definition: integer_rmap.F90:81
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_integer_rmap::integer_rmap_set_range
elemental subroutine integer_rmap_set_range(integer_rmap, n_range)
Sets the maximum range of the forward map.
Definition: integer_rmap.F90:64