FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
bucket_search.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2019 FrontISTR Commons
3 ! This software is released under the MIT License, see LICENSE.txt
4 !-------------------------------------------------------------------------------
8  use hecmw
9  implicit none
10 
11  private
12  public :: bucketdb
13  public :: bucketdb_init
14  public :: bucketdb_finalize
15  public :: bucketdb_setup
16  public :: bucketdb_getbucketid
17  public :: bucketdb_registerpre
18  public :: bucketdb_allocate
19  public :: bucketdb_register
20  public :: bucketdb_getnumcand
21  public :: bucketdb_getcand
22 
23  integer(kind=kint), parameter :: BUCKET_DEBUG = 0
24 
26  type bucket
27  integer(kind=kint) :: n
28  integer(kind=kint) :: n_max
29  integer(kind=kint), pointer :: member(:) => null()
30  end type bucket
31 
33  type bucketdb
34  private
35  real(kind=kreal) :: x_min(3)
36  real(kind=kreal) :: x_max(3)
37  real(kind=kreal) :: d(3)
38  integer(kind=kint) :: ndiv(3) = 0
39  type(bucket), pointer :: buckets(:,:,:) => null()
40  integer(kind=kint) :: n_tot = 0
41  integer(kind=kint), pointer :: member_all(:) => null()
42  end type bucketdb
43 
44 contains
45 
47  subroutine assert(cond, mesg)
48  implicit none
49  logical, intent(in) :: cond
50  character(len=*) :: mesg
51  if (bucket_debug > 0) then
52  if (.not. cond) then
53  write(0,*) 'ASSERTION FAILED: ',mesg
54  call hecmw_abort( hecmw_comm_get_comm() )
55  endif
56  endif
57  end subroutine assert
58 
59 !!!
60 !!! routines for type(bucket)
61 !!!
62 
64  subroutine bucket_init(bkt)
65  implicit none
66  type(bucket), intent(inout) :: bkt
67  bkt%n = 0
68  bkt%n_max = 0
69  nullify(bkt%member)
70  end subroutine bucket_init
71 
73  subroutine bucket_finalize(bkt)
74  implicit none
75  type(bucket), intent(inout) :: bkt
76  !if (bkt%n > 0) deallocate(bkt%member)
77  nullify(bkt%member)
78  bkt%n = 0
79  bkt%n_max = 0
80  end subroutine bucket_finalize
81 
83  subroutine bucket_incr_count(bkt)
84  implicit none
85  type(bucket), intent(inout) :: bkt
86  !$omp atomic
87  bkt%n = bkt%n + 1
88  end subroutine bucket_incr_count
89 
91  subroutine bucket_assign(bkt, mem)
92  implicit none
93  type(bucket), intent(inout) :: bkt
94  integer(kind=kint), pointer :: mem(:)
95  bkt%member => mem
96  bkt%n_max = bkt%n
97  bkt%n = 0
98  end subroutine bucket_assign
99 
101  subroutine bucket_register(bkt, sid)
102  implicit none
103  type(bucket), intent(inout) :: bkt
104  integer(kind=kint), intent(in) :: sid
105  integer(kind=kint) :: idx
106  !$omp atomic capture
107  bkt%n = bkt%n + 1
108  idx = bkt%n
109  !$omp end atomic
110  call assert(idx <= bkt%n_max, 'bucket_register: too many members')
111  bkt%member(idx) = sid
112  end subroutine bucket_register
113 
115  function bucket_get_n(bkt)
116  implicit none
117  integer(kind=kint) :: bucket_get_n
118  type(bucket), intent(in) :: bkt
119  bucket_get_n = bkt%n
120  end function bucket_get_n
121 
123  subroutine bucket_get_member(bkt, n, memb)
124  implicit none
125  type(bucket), intent(in) :: bkt
126  integer(kind=kint), intent(in) :: n
127  integer(kind=kint), intent(out) :: memb(n)
128  call assert(n == bkt%n, 'bucket_get_member: wrong n')
129  memb(1:n) = bkt%member(1:n)
130  end subroutine bucket_get_member
131 
132 !!!
133 !!! routines for type(bucketDB)
134 !!!
135 
137  subroutine bucketdb_init(bktdb)
138  implicit none
139  type(bucketdb), intent(inout) :: bktdb
140  bktdb%x_min(:) = 0.d0
141  bktdb%x_max(:) = 0.d0
142  bktdb%d(:) = 0.d0
143  bktdb%ndiv(:) = 0
144  nullify(bktdb%buckets)
145  bktdb%n_tot = 0
146  nullify(bktdb%member_all)
147  end subroutine bucketdb_init
148 
150  subroutine bucketdb_finalize(bktdb)
151  implicit none
152  type(bucketdb), intent(inout) :: bktdb
153  integer(kind=kint) :: i, j, k
154  if (bktdb%n_tot > 0) then
155  if(associated(bktdb%member_all)) deallocate(bktdb%member_all)
156  nullify(bktdb%member_all)
157  bktdb%n_tot = 0
158  endif
159  if (any(bktdb%ndiv == 0)) then
160  bktdb%ndiv(:) = 0
161  return
162  endif
163  if(associated(bktdb%buckets)) then
164  do k = 1, bktdb%ndiv(3)
165  do j = 1, bktdb%ndiv(2)
166  do i = 1, bktdb%ndiv(1)
167  call bucket_finalize(bktdb%buckets(i,j,k))
168  enddo
169  enddo
170  enddo
171  deallocate(bktdb%buckets)
172  nullify(bktdb%buckets)
173  endif
174  bktdb%ndiv(:) = 0
175  end subroutine bucketdb_finalize
176 
178  subroutine bucketdb_setup(bktdb, x_min, x_max, dmin, n_tot)
179  implicit none
180  type(bucketdb), intent(inout) :: bktdb
181  real(kind=kreal), intent(in) :: x_min(3)
182  real(kind=kreal), intent(in) :: x_max(3)
183  real(kind=kreal), intent(in) :: dmin
184  integer(kind=kint), intent(in) :: n_tot
185  real(kind=kreal) :: xrange(3)
186  integer(kind=kint) :: i, j, k
187  real(kind=kreal), parameter :: eps = 1.d-6
188  if (bucket_debug >= 1) write(0,*) 'DEBUG: bucketDB_setup', x_min, x_max, dmin, n_tot
189  if (associated(bktdb%buckets)) deallocate(bktdb%buckets)
190  bktdb%x_min(:) = x_min(:)
191  bktdb%x_max(:) = x_max(:)
192  xrange(:) = x_max(:) - x_min(:)
193  call assert(all(xrange > 0.d0), 'bucketDB_setup: invalid x_min, x_max')
194  do i = 1, 3
195  bktdb%ndiv(i) = max(floor(xrange(i) / dmin), 1)
196  bktdb%d(i) = xrange(i) / bktdb%ndiv(i) * (1.d0 + eps)
197  enddo
198  if (bucket_debug >= 1) write(0,*) 'DEBUG: bucketDB_setup: ndiv, d: ', bktdb%ndiv, bktdb%d
199  call assert(all(bktdb%d > 0.d0), 'bucketDB_setup: invalid bktdb%d')
200  allocate(bktdb%buckets(bktdb%ndiv(1), bktdb%ndiv(2), bktdb%ndiv(3)), stat=i)
201  if( i /= 0 ) then
202  write(*,*) 'Allocation error: bktdb%buckets', bktdb%ndiv
203  call hecmw_abort(hecmw_comm_get_comm())
204  endif
205  do k = 1, bktdb%ndiv(3)
206  do j = 1, bktdb%ndiv(2)
207  do i = 1, bktdb%ndiv(1)
208  call bucket_init(bktdb%buckets(i,j,k))
209  enddo
210  enddo
211  enddo
212  if (bktdb%n_tot /= n_tot) then
213  if (associated(bktdb%member_all)) deallocate(bktdb%member_all)
214  allocate(bktdb%member_all(n_tot))
215  bktdb%n_tot = n_tot
216  endif
217  end subroutine bucketdb_setup
218 
220  function encode_bid(bktdb, baddr)
221  implicit none
222  integer(kind=kint) :: encode_bid
223  type(bucketdb), intent(in) :: bktdb
224  integer(kind=kint), intent(in) :: baddr(3)
225  if (any(baddr <= 0) .or. any(baddr > bktdb%ndiv)) then
226  encode_bid = -1
227  else
228  encode_bid = &
229  (baddr(3)-1) * bktdb%ndiv(1) * bktdb%ndiv(2) + (baddr(2)-1) * bktdb%ndiv(1) + baddr(1)
230  endif
231  end function encode_bid
232 
234  function decode_bid(bktdb, bid)
235  implicit none
236  integer(kind=kint) :: decode_bid(3)
237  type(bucketdb), intent(in) :: bktdb
238  integer(kind=kint), intent(in) :: bid
239  call assert(bid <= bktdb%ndiv(1)*bktdb%ndiv(2)*bktdb%ndiv(3), 'decode_bid: out of range')
240  if (bid < 0) then
241  decode_bid(:) = -1
242  else
243  decode_bid(1) = mod(bid-1, bktdb%ndiv(1)) + 1
244  decode_bid(2) = mod((bid-1)/bktdb%ndiv(1), bktdb%ndiv(2)) + 1
245  decode_bid(3) = (bid-1)/(bktdb%ndiv(1) * bktdb%ndiv(2)) + 1
246  call assert(encode_bid(bktdb, decode_bid) == bid, 'decode_bid')
247  endif
248  end function decode_bid
249 
251  function bucketdb_getbucketid(bktdb, x)
252  implicit none
253  integer(kind=kint) :: bucketdb_getbucketid
254  type(bucketdb), intent(in) :: bktdb
255  real(kind=kreal), intent(in) :: x(3)
256  integer(kind=kint) :: baddr(3)
257  integer(kind=kint) :: i
258  if (bktdb%n_tot == 0) then
260  return
261  endif
262  do i = 1, 3
263  call assert(bktdb%d(i) > 0.d0, 'bucketDB_getBucketID: bktdb%d(i) is zero')
264  baddr(i) = floor((x(i) - bktdb%x_min(i)) / bktdb%d(i)) + 1
265  enddo
266  if (bucket_debug >= 2) write(0,*) ' DEBUG: bucketDB_getBucketID: ',x,baddr
267  bucketdb_getbucketid = encode_bid(bktdb, baddr)
268  end function bucketdb_getbucketid
269 
272  subroutine bucketdb_registerpre(bktdb, bid)
273  implicit none
274  type(bucketdb), intent(inout) :: bktdb
275  integer(kind=kint), intent(in) :: bid
276  integer(kind=kint) :: baddr(3)
277  baddr = decode_bid(bktdb, bid)
278  call assert(all(baddr > 0) .and. all(baddr <= bktdb%ndiv), 'bucketDB_register_pre: block ID out of range')
279  call bucket_incr_count(bktdb%buckets(baddr(1),baddr(2),baddr(3)))
280  if (bucket_debug >= 2) write(0,*) ' DEBUG: bucketDB_registerPre: ', baddr
281  end subroutine bucketdb_registerpre
282 
285  subroutine bucketdb_allocate(bktdb)
286  implicit none
287  type(bucketdb), intent(inout) :: bktdb
288  integer(kind=kint) :: i, j, k, count, n
289  integer(kind=kint), pointer :: pmemb(:)
290  count = 0
291  do k = 1, bktdb%ndiv(3)
292  do j = 1, bktdb%ndiv(2)
293  do i = 1, bktdb%ndiv(1)
294  !call bucket_allocate(bktdb%buckets(i,j,k))
295  n = bucket_get_n(bktdb%buckets(i,j,k))
296  pmemb => bktdb%member_all(count+1:count+n)
297  call bucket_assign(bktdb%buckets(i,j,k), pmemb)
298  count = count + n
299  enddo
300  enddo
301  enddo
302  end subroutine bucketdb_allocate
303 
306  subroutine bucketdb_register(bktdb, bid, sid)
307  implicit none
308  type(bucketdb), intent(inout) :: bktdb
309  integer(kind=kint), intent(in) :: bid
310  integer(kind=kint), intent(in) :: sid
311  integer(kind=kint) :: baddr(3)
312  baddr = decode_bid(bktdb, bid)
313  call assert(all(baddr > 0) .and. all(baddr <= bktdb%ndiv), 'bucketDB_register: block ID our of range')
314  call bucket_register(bktdb%buckets(baddr(1),baddr(2),baddr(3)), sid)
315  if (bucket_debug >= 2) write(0,*) ' DEBUG: bucketDB_register: ', baddr, sid
316  end subroutine bucketdb_register
317 
320  function bucketdb_getnumcand(bktdb, bid)
321  implicit none
322  integer(kind=kint) :: bucketdb_getnumcand
323  type(bucketdb), intent(in) :: bktdb
324  integer(kind=kint), intent(in) :: bid
325  integer(kind=kint) :: baddr(3), ncand, i, j, k, is, ie, js, je, ks, ke
326  if (bid < 0) then
328  return
329  endif
330  baddr = decode_bid(bktdb, bid)
331  ncand = 0
332  is = max(baddr(1)-1, 1)
333  ie = min(baddr(1)+1, bktdb%ndiv(1))
334  js = max(baddr(2)-1, 1)
335  je = min(baddr(2)+1, bktdb%ndiv(2))
336  ks = max(baddr(3)-1, 1)
337  ke = min(baddr(3)+1, bktdb%ndiv(3))
338  do k = ks, ke
339  do j = js, je
340  do i = is, ie
341  ncand = ncand + bucket_get_n(bktdb%buckets(i,j,k))
342  enddo
343  enddo
344  enddo
345  bucketdb_getnumcand = ncand
346  if (bucket_debug >= 2) write(0,*) ' DEBUG: bucketDB_getNumCand: ',ncand
347  end function bucketdb_getnumcand
348 
351  subroutine bucketdb_getcand(bktdb, bid, ncand, cand)
352  implicit none
353  type(bucketdb), intent(in) :: bktdb
354  integer(kind=kint), intent(in) :: bid
355  integer(kind=kint), intent(in) :: ncand
356  integer(kind=kint), intent(out), target :: cand(ncand)
357  integer(kind=kint) :: baddr(3), i, j, k, n, cnt, is, ie, js, je, ks, ke
358  integer(kind=kint), pointer :: pcand(:)
359  if (bid < 0 .or. ncand == 0) return
360  baddr = decode_bid(bktdb, bid)
361  cnt = 0
362  is = max(baddr(1)-1, 1)
363  ie = min(baddr(1)+1, bktdb%ndiv(1))
364  js = max(baddr(2)-1, 1)
365  je = min(baddr(2)+1, bktdb%ndiv(2))
366  ks = max(baddr(3)-1, 1)
367  ke = min(baddr(3)+1, bktdb%ndiv(3))
368  do k = ks, ke
369  do j = js, je
370  do i = is, ie
371  n = bucket_get_n(bktdb%buckets(i,j,k))
372  pcand => cand(cnt+1:cnt+n)
373  call bucket_get_member(bktdb%buckets(i,j,k), n, pcand)
374  cnt = cnt + n
375  call assert(cnt <= ncand, 'bucketDB_get_cand: array overflow')
376  enddo
377  enddo
378  enddo
379  call assert(cnt == ncand, 'bucketDB_get_cand: count mismatch')
380  if (bucket_debug >= 3) write(0,*) ' DEBUG: bucketDB_getCand: ',cand
381  end subroutine bucketdb_getcand
382 
383 end module bucket_search
This module provides bucket-search functionality It provides definition of bucket info and its access...
subroutine, public bucketdb_allocate(bktdb)
Allocate memory before actually registering members Before allocating memory, bucketDB_registerPre ha...
subroutine, public bucketdb_registerpre(bktdb, bid)
Pre-register for just counting members to be actually registered Bucket ID has to be obtained with bu...
integer(kind=kint) function, public bucketdb_getbucketid(bktdb, x)
Get bucket ID that includes given point.
subroutine, public bucketdb_register(bktdb, bid, sid)
Register member Before actually register, bucketDB_allocate has to be called.
subroutine, public bucketdb_finalize(bktdb)
Finalizer.
integer(kind=kint) function, public bucketdb_getnumcand(bktdb, bid)
Get number of candidates within neighboring buckets of a given bucket Bucket ID has to be obtained wi...
subroutine, public bucketdb_init(bktdb)
Initializer.
subroutine, public bucketdb_getcand(bktdb, bid, ncand, cand)
Get candidates within neighboring buckets of a given bucket Number of candidates has to be obtained w...
subroutine, public bucketdb_setup(bktdb, x_min, x_max, dmin, n_tot)
Setup basic info of buckets.
Definition: hecmw.f90:6