File: N:\mfix\model\des\sap.f
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "version.inc"
14
15 module sweep_and_prune
16
17 use pair_manager
18 use list
19
20
21 type endpoint_t
22
23
24
25 integer(kind=4) :: box_id
26
27
28 real :: value
29 end type endpoint_t
30
31
32
33
34
35
36
37
38
39
40 type aabb_t
41 real :: maxendpoint(3)
42 real :: minendpoint(3)
43 end type aabb_t
44
45
46
47
48
49
50
51
52
53
54
55
56 type box_t
57 integer :: maxendpoint_id(3)
58 integer :: minendpoint_id(3)
59 integer :: particle_id
60 end type box_t
61
62
63
64
65
66
67
68
69
70
71 type sap_t
72
73 integer :: id
74
75
76 type(endpoint_t), dimension(:), allocatable :: x_endpoints
77 type(endpoint_t), dimension(:), allocatable :: y_endpoints
78 type(endpoint_t), dimension(:), allocatable :: z_endpoints
79 integer :: x_endpoints_len
80 integer :: y_endpoints_len
81 integer :: z_endpoints_len
82
83
84 type(box_t), dimension(:), allocatable :: boxes
85 integer :: boxes_len
86
87
88 type(list_t) :: deleted_boxes
89
90
91 type(hashtable_t) :: hashtable
92 end type sap_t
93
94 public :: init_sap, add_box, del_box, update_box, sort, sweep
95 private :: partition, fullcheck, boxes_grow, endpoints_grow, sort_endpoints, quicksort_endpoints
96
97 contains
98
99 subroutine check(this)
100 use discretelement
101 implicit none
102 type(sap_t), intent(inout) :: this
103 integer :: ii, pid
104 do ii = 1, this%x_endpoints_len
105
106 if (0 > this%x_endpoints(ii)%box_id) then
107
108 if (ii .ne. this%boxes(-this%x_endpoints(ii)%box_id)%minendpoint_id(1) ) then
109 print *,"ii is ",ii
110 print *,"this%x_endpoints(ii)%box_id is ",this%x_endpoints(ii)%box_id
111 print *,"this%boxes(this%x_endpoints(ii)%box_id)%minendpoint_id(1)",this%boxes(-this%x_endpoints(ii)%box_id)%minendpoint_id(1)
112 stop __LINE__
113 endif
114 else
115 if (ii .ne. this%boxes(this%x_endpoints(ii)%box_id)%maxendpoint_id(1) ) then
116 print *,"ii is ",ii
117 print *,"this%x_endpoints(ii)%box_id is ",this%x_endpoints(ii)%box_id
118 print *,"this%boxes(this%x_endpoints(ii)%box_id)%minendpoint_id(1)",this%boxes(this%x_endpoints(ii)%box_id)%maxendpoint_id(1)
119
120 stop __LINE__
121 endif
122 endif
123 enddo
124
125 do ii = 1, this%y_endpoints_len
126 if (0 > this%y_endpoints(ii)%box_id) then
127 if (ii .ne. this%boxes(-this%y_endpoints(ii)%box_id)%minendpoint_id(2) ) then
128 print *,"ii is ",ii
129 print *,"this%y_endpoints(ii)%box_id is ",this%y_endpoints(ii)%box_id
130 print *,"this%boxes(this%y_endpoints(ii)%box_id)%minendpoint_id(1)",this%boxes(-this%y_endpoints(ii)%box_id)%minendpoint_id(2)
131
132 stop __LINE__
133 endif
134 else
135 if (ii .ne. this%boxes(this%y_endpoints(ii)%box_id)%maxendpoint_id(2) ) then
136 stop __LINE__
137 endif
138 endif
139 enddo
140
141 do ii = 1, this%z_endpoints_len
142 if (0 > this%z_endpoints(ii)%box_id) then
143 if (ii .ne. this%boxes(-this%z_endpoints(ii)%box_id)%minendpoint_id(3) ) then
144 stop __LINE__
145 endif
146 else
147 if (ii .ne. this%boxes(this%z_endpoints(ii)%box_id)%maxendpoint_id(3) ) then
148 stop __LINE__
149 endif
150 endif
151 enddo
152
153 do ii = 1, this%boxes_len
154 pid = this%boxes(ii)%particle_id
155 if ( 0.0001 < abs(this%x_endpoints(this%boxes(ii)%maxendpoint_id(1))%value - this%x_endpoints(this%boxes(ii)%minendpoint_id(1))%value - 2*des_radius(pid))) then
156
157 print *,this%x_endpoints(this%boxes(ii)%maxendpoint_id(1))%value
158 print *,this%x_endpoints(this%boxes(ii)%minendpoint_id(1))%value
159 print *,2*des_radius(pid)
160
161 stop __LINE__
162 endif
163 enddo
164
165 do ii = 1, this%boxes_len
166 pid = this%boxes(ii)%particle_id
167 if ( 0.0001 < abs(this%y_endpoints(this%boxes(ii)%maxendpoint_id(2))%value - this%y_endpoints(this%boxes(ii)%minendpoint_id(2))%value - 2*des_radius(pid))) then
168 stop __LINE__
169 endif
170 enddo
171
172 do ii = 1, this%boxes_len
173 pid = this%boxes(ii)%particle_id
174 if ( 0.0001 < abs(this%z_endpoints(this%boxes(ii)%maxendpoint_id(3))%value - this%z_endpoints(this%boxes(ii)%minendpoint_id(3))%value - 2*des_radius(pid))) then
175 stop __LINE__
176 endif
177 enddo
178
179 end subroutine check
180
181
182
183
184
185
186
187
188
189 subroutine init_sap(this,id)
190 implicit none
191 type(sap_t), intent(inout) :: this
192 integer, intent(in) :: id
193
194 this%x_endpoints_len = 0
195 this%y_endpoints_len = 0
196 this%z_endpoints_len = 0
197 this%boxes_len = 0
198 this%id = id
199
200 allocate (this%x_endpoints(10))
201 allocate (this%y_endpoints(10))
202 allocate (this%z_endpoints(10))
203 allocate (this%boxes(10))
204
205 call list_init(this%deleted_boxes)
206
207 call init_pairs(this%hashtable)
208
209 end subroutine init_sap
210
211
212
213
214
215
216
217
218
219 SUBROUTINE boxes_GROW(box_array,new_size)
220 IMPLICIT NONE
221
222 INTEGER, INTENT(IN) :: new_size
223 type(box_t), DIMENSION(:), ALLOCATABLE, INTENT(INOUT) :: box_array
224 type(box_t), DIMENSION(:), ALLOCATABLE :: box_tmp
225 INTEGER lSIZE
226
227 lSIZE = size(box_array,1)
228 allocate(box_tmp(new_size))
229 box_tmp(1:lSIZE) = box_array(1:lSIZE)
230 call move_alloc(box_tmp,box_array)
231
232 END SUBROUTINE boxes_GROW
233
234
235
236
237
238
239
240
241
242 SUBROUTINE endpoints_GROW(endpoint_array,new_size)
243 IMPLICIT NONE
244
245 INTEGER, INTENT(IN) :: new_size
246 type(endpoint_t), DIMENSION(:), ALLOCATABLE, INTENT(INOUT) :: endpoint_array
247 type(endpoint_t), DIMENSION(:), ALLOCATABLE :: endpoint_tmp
248 INTEGER lSIZE
249
250 lSIZE = size(endpoint_array,1)
251 allocate(endpoint_tmp(new_size))
252 endpoint_tmp(1:lSIZE) = endpoint_array(1:lSIZE)
253 call move_alloc(endpoint_tmp,endpoint_array)
254
255 END SUBROUTINE endpoints_GROW
256
257
258
259
260
261
262
263
264
265
266 subroutine add_box(this,aabb,particle_id,id)
267
268 implicit none
269 type(sap_t), intent(inout) :: this
270 type(aabb_t), intent(in) :: aabb
271 integer, intent(in) :: particle_id
272 integer, intent(out) :: id
273
274 if (this%x_endpoints_len+2 > size(this%x_endpoints)) then
275 call endpoints_GROW(this%x_endpoints,2*(this%x_endpoints_len+2))
276 endif
277
278 if (this%y_endpoints_len+2 > size(this%y_endpoints)) then
279 call endpoints_GROW(this%y_endpoints,2*(this%y_endpoints_len+2))
280 endif
281
282 if (this%z_endpoints_len+2 > size(this%z_endpoints)) then
283 call endpoints_GROW(this%z_endpoints,2*(this%z_endpoints_len+2))
284 endif
285
286 if (this%boxes_len+1 > size(this%boxes)) then
287 call boxes_GROW(this%boxes,2*(this%boxes_len+1))
288 endif
289
290 id = list_pop(this%deleted_boxes)
291
292
293
294 if ( id < 0 ) then
295 this%boxes_len = this%boxes_len + 1
296 id = this%boxes_len
297 endif
298
299
300 %x_endpoints_len = this%x_endpoints_len + 2
301 this%y_endpoints_len = this%y_endpoints_len + 2
302 this%z_endpoints_len = this%z_endpoints_len + 2
303
304 this%boxes(id)%particle_id = particle_id
305 this%boxes(id)%maxendpoint_id(1) = this%x_endpoints_len
306 this%boxes(id)%maxendpoint_id(2) = this%y_endpoints_len
307 this%boxes(id)%maxendpoint_id(3) = this%z_endpoints_len
308 this%boxes(id)%minendpoint_id(1) = this%x_endpoints_len-1
309 this%boxes(id)%minendpoint_id(2) = this%y_endpoints_len-1
310 this%boxes(id)%minendpoint_id(3) = this%z_endpoints_len-1
311
312 this%x_endpoints(this%x_endpoints_len-1)%box_id = -id
313 this%x_endpoints(this%x_endpoints_len-1)%value = aabb%minendpoint(1)
314 this%y_endpoints(this%y_endpoints_len-1)%box_id = -id
315 this%y_endpoints(this%y_endpoints_len-1)%value = aabb%minendpoint(2)
316 this%z_endpoints(this%z_endpoints_len-1)%box_id = -id
317 this%z_endpoints(this%z_endpoints_len-1)%value = aabb%minendpoint(3)
318
319 this%x_endpoints(this%x_endpoints_len)%box_id = id
320 this%x_endpoints(this%x_endpoints_len)%value = aabb%maxendpoint(1)
321 this%y_endpoints(this%y_endpoints_len)%box_id = id
322 this%y_endpoints(this%y_endpoints_len)%value = aabb%maxendpoint(2)
323 this%z_endpoints(this%z_endpoints_len)%box_id = id
324 this%z_endpoints(this%z_endpoints_len)%value = aabb%maxendpoint(3)
325
326 end subroutine add_box
327
328
329
330
331
332
333
334
335
336
337
338
339 subroutine del_box(this,id)
340 implicit none
341 type(sap_t), intent(inout) :: this
342 integer, intent(in) :: id
343
344 this%x_endpoints(this%boxes(id)%maxendpoint_id(1))%value = HUGE(0.0)
345 this%y_endpoints(this%boxes(id)%maxendpoint_id(2))%value = HUGE(0.0)
346 this%z_endpoints(this%boxes(id)%maxendpoint_id(3))%value = HUGE(0.0)
347 this%x_endpoints(this%boxes(id)%minendpoint_id(1))%value = HUGE(0.0)
348 this%y_endpoints(this%boxes(id)%minendpoint_id(2))%value = HUGE(0.0)
349 this%z_endpoints(this%boxes(id)%minendpoint_id(3))%value = HUGE(0.0)
350
351 end subroutine del_box
352
353
354
355
356
357
358
359
360
361 subroutine update_box(this,id,aabb)
362 implicit none
363 type(sap_t), intent(inout) :: this
364 integer, intent(in) :: id
365 type(aabb_t), intent(in) :: aabb
366
367
368 %x_endpoints(this%boxes(id)%maxendpoint_id(1))%value = aabb%maxendpoint(1)
369 this%y_endpoints(this%boxes(id)%maxendpoint_id(2))%value = aabb%maxendpoint(2)
370 this%z_endpoints(this%boxes(id)%maxendpoint_id(3))%value = aabb%maxendpoint(3)
371 this%x_endpoints(this%boxes(id)%minendpoint_id(1))%value = aabb%minendpoint(1)
372 this%y_endpoints(this%boxes(id)%minendpoint_id(2))%value = aabb%minendpoint(2)
373 this%z_endpoints(this%boxes(id)%minendpoint_id(3))%value = aabb%minendpoint(3)
374
375 end subroutine update_box
376
377
378
379
380
381
382
383
384
385
386
387
388
389 subroutine sort(this)
390 use geometry, only: do_k
391 implicit none
392 type(sap_t), intent(inout) :: this
393 integer :: ii
394
395
396 call sort_endpoints(this,this%x_endpoints(1:this%x_endpoints_len),1)
397 call sort_endpoints(this,this%y_endpoints(1:this%y_endpoints_len),2)
398 if (do_k) call sort_endpoints(this,this%z_endpoints(1:this%z_endpoints_len),3)
399
400
401
402
403
404
405
406
407
408
409
410
411 = this%x_endpoints_len
412 do
413 if (ii .le. 0) exit
414 if (this%x_endpoints(ii)%value .ne. HUGE(0.0)) exit
415 this%boxes(abs(this%x_endpoints(ii)%box_id))%minendpoint_id(:) = 0
416 this%boxes(abs(this%x_endpoints(ii)%box_id))%maxendpoint_id(:) = 0
417 call list_add(this%deleted_boxes,this%x_endpoints(ii)%box_id)
418 ii = ii - 1
419 enddo
420
421 this%x_endpoints_len = ii
422 this%y_endpoints_len = ii
423 this%z_endpoints_len = ii
424
425 end subroutine sort
426
427
428
429
430
431
432
433
434
435
436
437 subroutine sweep(this)
438
439 use pair_manager, only: add_pair
440 use geometry, only: no_k
441
442 implicit none
443 type(sap_t), intent(inout) :: this
444
445
446 integer :: ii,aa,minmax,ai
447
448 type(list_t) :: active
449
450 call list_init(active)
451
452 do ii=1, this%x_endpoints_len
453
454 minmax = this%x_endpoints(ii)%box_id
455
456 if ( minmax < 0) then
457
458
459 do ai=1, list_get_length(active)
460 aa = list_get(active,ai)
461
462
463 if (max(this%boxes(aa)%minendpoint_id(2),this%boxes(-minmax)%minendpoint_id(2)) <= min(this%boxes(-minmax)%maxendpoint_id(2),this%boxes(aa)%maxendpoint_id(2)) .and. &
464 (NO_K .or. max(this%boxes(aa)%minendpoint_id(3),this%boxes(-minmax)%minendpoint_id(3)) <= min(this%boxes(-minmax)%maxendpoint_id(3),this%boxes(aa)%maxendpoint_id(3)))) then
465 call add_pair(this%hashtable,this%boxes(-minmax)%particle_id,this%boxes(aa)%particle_id)
466 endif
467 enddo
468
469
470 call list_add(active,-minmax)
471
472 else if ( 0 < minmax ) then
473
474 call list_del(active,minmax)
475 else
476 print *,"SAP_ID=",this%id,"minmax shouldn't be zero: ",minmax
477 ERROR_STOP __LINE__
478 endif
479 enddo
480
481 end subroutine sweep
482
483
484
485
486
487
488
489
490
491
492
493
494
495 subroutine sort_endpoints(this, endpoints, axis)
496 use pair_manager, only: add_pair, del_pair
497 implicit none
498 type(sap_t), intent(inout) :: this
499 integer, intent(in) :: axis
500 type(endpoint_t), dimension(:), intent(inout) :: endpoints
501 integer :: ii, jj
502 type(endpoint_t) :: sweeppoint, swappoint
503 real :: sweepval
504
505 do ii=2, size(endpoints)
506
507 sweeppoint = endpoints(ii)
508 sweepval = sweeppoint%value
509 jj = ii-1
510
511 do while ( 0 < jj )
512 if ( endpoints(jj)%value <= sweepval ) then
513 exit
514 endif
515
516 swappoint = endpoints(jj)
517
518 if (sweeppoint%box_id < 0 .and. 0 < swappoint%box_id ) then
519 if (fullcheck(this,-sweeppoint%box_id,swappoint%box_id,axis)) then
520 call add_pair(this%hashtable,this%boxes(-sweeppoint%box_id)%particle_id,this%boxes(swappoint%box_id)%particle_id)
521 endif
522 endif
523
524 if (0 < sweeppoint%box_id .and. swappoint%box_id < 0 ) then
525 if (fullcheck(this,sweeppoint%box_id,-swappoint%box_id,axis)) then
526 call del_pair(this%hashtable,this%boxes(sweeppoint%box_id)%particle_id,this%boxes(-swappoint%box_id)%particle_id)
527 endif
528 endif
529
530 endpoints(jj+1) = swappoint
531
532
533 if (swappoint%box_id < 0) then
534 this%boxes(-swappoint%box_id)%minendpoint_id(axis) = jj+1
535 else if (swappoint%box_id > 0) then
536 this%boxes(swappoint%box_id)%maxendpoint_id(axis) = jj+1
537 endif
538
539 jj = jj - 1
540 enddo
541
542 endpoints(jj+1) = sweeppoint
543
544
545 if (sweeppoint%box_id < 0) then
546 this%boxes(-sweeppoint%box_id)%minendpoint_id(axis) = jj+1
547 else if (sweeppoint%box_id > 0) then
548 this%boxes(sweeppoint%box_id)%maxendpoint_id(axis) = jj+1
549 endif
550
551 enddo
552
553 end subroutine sort_endpoints
554
555
556
557
558
559
560
561
562
563
564 logical function fullcheck(this,id,id2,curr_axis)
565 use geometry, only: no_k
566 implicit none
567 type(sap_t), intent(inout) :: this
568
569 integer, intent(in) :: id, id2, curr_axis
570
571 fullcheck = ((curr_axis.eq.1 .or. max(this%boxes(id)%minendpoint_id(1),this%boxes(id2)%minendpoint_id(1)) &
572 <= min(this%boxes(id2)%maxendpoint_id(1),this%boxes(id)%maxendpoint_id(1))) &
573 .and. (curr_axis.eq.2 .or. max(this%boxes(id)%minendpoint_id(2),this%boxes(id2)%minendpoint_id(2)) &
574 <= min(this%boxes(id2)%maxendpoint_id(2),this%boxes(id)%maxendpoint_id(2))) &
575 .and. (NO_K .or. curr_axis.eq.3 .or. max(this%boxes(id)%minendpoint_id(3),this%boxes(id2)%minendpoint_id(3)) &
576 <= min(this%boxes(id2)%maxendpoint_id(3),this%boxes(id)%maxendpoint_id(3))))
577
578 end function fullcheck
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593 subroutine quicksort(this)
594 implicit none
595 type(sap_t), intent(inout) :: this
596
597 call quicksort_endpoints(this,this%x_endpoints(1:this%x_endpoints_len),1)
598 call quicksort_endpoints(this,this%y_endpoints(1:this%y_endpoints_len),2)
599 call quicksort_endpoints(this,this%z_endpoints(1:this%z_endpoints_len),3)
600
601 end subroutine quicksort
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 recursive subroutine quicksort_endpoints(this, endpoints, axis)
618 type(sap_t), intent(inout) :: this
619 integer, intent(in) :: axis
620 type(endpoint_t), intent(inout), dimension(:) :: endpoints
621 integer :: ii
622
623
624
625 if(size(endpoints) > 1) then
626 call partition(this, endpoints, ii, axis)
627 call quicksort_endpoints(this,endpoints(:ii-1),axis)
628 call quicksort_endpoints(this,endpoints(ii:),axis)
629 endif
630
631 end subroutine quicksort_endpoints
632
633
634
635
636
637
638
639
640
641
642 subroutine partition(this, endpoints, marker, axis)
643 type(sap_t), intent(inout) :: this
644 integer, intent(in) :: axis
645 type(endpoint_t), intent(in out), dimension(:) :: endpoints
646 integer, intent(out) :: marker
647 type(endpoint_t) :: temp
648 integer :: tmp_ii, tmp_jj
649 integer :: i, j
650 real :: x
651 = endpoints(1)%value
652 i= 0
653 j= size(endpoints) + 1
654
655 do
656 j = j-1
657 do
658 if (endpoints(j)%value <= x) exit
659 j = j-1
660 end do
661 i = i+1
662 do
663 if (endpoints(i)%value >= x) exit
664 i = i+1
665 end do
666 if (i < j) then
667
668
669 if (endpoints(i)%box_id < 0) then
670 tmp_ii = this%boxes(-endpoints(i)%box_id)%minendpoint_id(axis)
671 else
672 tmp_ii = this%boxes(endpoints(i)%box_id)%maxendpoint_id(axis)
673 endif
674 if (endpoints(j)%box_id < 0) then
675 tmp_jj = this%boxes(-endpoints(j)%box_id)%minendpoint_id(axis)
676 else
677 tmp_jj = this%boxes(endpoints(j)%box_id)%maxendpoint_id(axis)
678 endif
679
680 temp = endpoints(i)
681 endpoints(i) = endpoints(j)
682 endpoints(j) = temp
683
684 if (endpoints(i)%box_id < 0) then
685 this%boxes(-endpoints(i)%box_id)%minendpoint_id(axis) = tmp_ii
686 else
687 this%boxes(endpoints(i)%box_id)%maxendpoint_id(axis) = tmp_ii
688 endif
689 if (endpoints(j)%box_id < 0) then
690 this%boxes(-endpoints(j)%box_id)%minendpoint_id(axis) = tmp_jj
691 else
692 this%boxes(endpoints(j)%box_id)%maxendpoint_id(axis) = tmp_jj
693 endif
694
695 elseif (i == j) then
696 marker = i+1
697 return
698 else
699 marker = i
700 return
701 endif
702 end do
703
704 end subroutine partition
705
706 end module sweep_and_prune
707