MFIX  2016-1
des_cluster_mod.f
Go to the documentation of this file.
1 !vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv!
2 ! !
3 ! Module name: DES_CLUSTER !
4 ! !
5 ! Purpose: Common elements for MFIX-DEM cluster identification !
6 ! condition. !
7 ! !
8 ! Author: J.Galvin, J.Musser Date: Nov-12 !
9 ! Modified: S. Benyahia Date: Dec-12 !
10 ! !
11 ! Comments: Info on clusters such as average void fraction, Re and !
12 ! Comments: cluster size can now be printed from this file !
13 ! !
14 !^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!
15  MODULE des_cluster
16 
17 
18 !-----------------------------------------------
19 ! Modules
20 !-----------------------------------------------
21  USE param
22  USE param1
23  USE compar
24  USE fldvar
25  USE physprop
26  USE discretelement
27 
28  use mpi_utility
29  use desmpi_wrapper
30  use desmpi
31  use compar
32  use desmpi
33  use parallel
34  use sendrecv
35 
36 
37  IMPLICIT NONE
38 !-----------------------------------------------
39 
40 
41 ! Number of clusters.
42  INTEGER clustercount
43 
44 ! Number of base particles held in current search list
46 
47 !----------------------------------------------->>>
49 ! Global index of particle.
50  INTEGER :: id
51 ! Successor in particle list
52  type(particle_type), POINTER :: next_particle
53  END TYPE particle_type
54 !-----------------------------------------------<<<
55 
56 ! Basic particle link-list.
58 
59 !----------------------------------------------->>>
61 ! Cluster index.
62  INTEGER :: id
63 ! Number of particles in cluster.
64  INTEGER :: particlecount
65 ! Successor in cluster link-list.
66  type(cluster_type), POINTER :: next_cluster
67 ! Particle link-list
68  type(particle_type), POINTER :: particle_ll
69  END TYPE cluster_type
70 !-----------------------------------------------<<<
71 
72 ! Cluster link-list.
73  TYPE(cluster_type), POINTER :: cluster_ll
74 
75 
76 
77 ! Process that does global cluster calculations.
78  integer, parameter :: clusterpe = 0
79 
80  TYPE ptype
81  INTEGER :: map
82  INTEGER :: id
83 ! Successor in particle list
84  type(ptype), POINTER :: next
85  END TYPE ptype
86 
87 
88  TYPE ctype
89 ! Number of particles in cluster.
90  INTEGER :: size
91 ! Particle link-list
92  type(ptype), POINTER :: particle
93  END TYPE ctype
94 
95 ! Cluster array.
96  TYPE(ctype), dimension(:), allocatable, target :: clusters
98 
99 ! Send/Recv information:
100 !----------------------->>
101 
102 ! Number of data entrires being sent from the local process to Root
103 ! during a call to cluster_gather.
104  INTEGER send_cnt
105 
106 ! Number of data entries being received by root from each process
107 ! during a call to cluster_gather.
108  INTEGER, dimension(:), allocatable :: recv_cnt
109 
110 ! Displacement of data from all processes during a cluster_gather.
111  INTEGER, dimension(:), allocatable :: recv_dsp
112 
113 ! Size of array needed by Root to accept all data during a gather call.
114  INTEGER recv_sum
115 
116 
117 ! Module interfaces:
118 !----------------------->>
119 
121  module procedure getclusterparticledata_1i
122  module procedure getclusterparticledata_2i
123  module procedure getclusterparticledata_1d
124  module procedure getclusterparticledata_2d
125  end interface
126 
128  module procedure getclusterfielddata_1d
129  module procedure getclusterfielddata_3d
130  end interface
131 
132  interface sendclusterdata
133  module procedure sendclusterdata_1d
134  end interface
135 
136 
137  contains
138 
139 !......................................................................!
140 ! !
141 !......................................................................!
142  SUBROUTINE create_cluster(cluster)
144  TYPE(cluster_type), INTENT(OUT), POINTER :: cluster
145 
146  ALLOCATE(cluster)
147 
148  NULLIFY(cluster%next_cluster)
149  NULLIFY(cluster%PARTICLE_LL)
150 
151  if(clustercount == 0) then
152 ! no clusters have been created/identified
153  if(associated(cluster_ll)) then
154  print*, ' Error - cluster pointer already associated!'
155  CALL mfix_exit(mype)
156  else
157  clustercount = 1
158  cluster%ParticleCount = 0
159  cluster%ID = clustercount
160 ! create first cluster of linked list of clusters. with cluster_ll
161 ! always being the 'first' in the list
162  cluster_ll => cluster
163  endif
164  else
165  if(.NOT.associated(cluster_ll)) then
166  print*, ' Error - cluster pointer is not associated!'
167  CALL mfix_exit(mype)
168  else
170  cluster%ParticleCount = 0
171  cluster%ID = clustercount
172 ! establish the link between the new cluster and existing cluster list
173  cluster%next_cluster => cluster_ll
174 ! reassign/point cluster_ll to be 'first' in the linked list
175  cluster_ll => cluster
176 ! as a result the linked list of clusters is created from 'bottom-up'
177 ! with the new cluster always being inserted before any existing
178 ! clusters
179  endif
180  ENDIF
181 
182  END SUBROUTINE create_cluster
183 
184 
185 !......................................................................!
186 ! !
187 !......................................................................!
188  SUBROUTINE gettopcluster(cluster)
190  TYPE(cluster_type), INTENT(INOUT), POINTER :: cluster
191 
192  NULLIFY(cluster)
193 
194 ! first check that a list has been formed
195  if(.NOT.associated(cluster_ll) .AND. clustercount == 0) then
196  write(*,"(//,3x,A,//)") 'No clusters to delete!'
197  elseif(.NOT.associated(cluster_ll) .AND. clustercount /= 0) then
198  write(*,"(//,3x,A,//)") ' Error with ClusterCount and pointer - Er:1'
199  elseif(associated(cluster_ll) .AND. clustercount == 0) then
200  write(*,"(//,3x,A,//)") ' Error with ClusterCount and pointer - Er:2'
201  else
202 ! now identify top cluster
203  CALL getnextcluster(cluster)
204  endif
205  END SUBROUTINE gettopcluster
206 
207 
208 !......................................................................!
209 ! !
210 !......................................................................!
211  SUBROUTINE deletetopcluster(cluster)
213  TYPE(cluster_type), INTENT(INOUT), POINTER :: cluster
214 
215 ! dbg
216 ! write(*,"(/A,I7)")' Deleting top cluster: ',cluster%ID
217  CALL delete_particles_in_cluster(cluster)
218 
219  if(associated(cluster%next_cluster)) then
220  cluster_ll => cluster%next_cluster
221  else
222  NULLIFY(cluster_ll)
223  endif
224 
226  NULLIFY(cluster%next_cluster)
227  NULLIFY(cluster%PARTICLE_LL)
228  DEALLOCATE(cluster)
229  NULLIFY(cluster)
230 
231  if(clustercount <0) then
232  write(*,"()")' ClusterCount < 0'
233  CALL mfix_exit(mype)
234  endif
235 
236  END SUBROUTINE deletetopcluster
237 
238 
239 !......................................................................!
240 ! !
241 !......................................................................!
242  SUBROUTINE delete_clusters()
244  TYPE(cluster_type), POINTER :: cluster
245  INTEGER cL, cDeleted
246 
247  NULLIFY(cluster)
248  cdeleted = 0
249 
250  if(.NOT.associated(cluster_ll) .AND. clustercount == 0) then
251 ! write(*,"(//,3x,A,//)") 'No clusters to delete!'
252  elseif(.NOT.associated(cluster_ll) .AND. clustercount /= 0) then
253  write(*,"(//,3x,A,//)") ' Error with ClusterCount and pointer - Er:1'
254  elseif(associated(cluster_ll) .AND. clustercount == 0) then
255  write(*,"(//,3x,A,//)") ' Error with ClusterCount and pointer - Er:2'
256  else
257  do cl =1, clustercount
258  CALL getnextcluster(cluster)
259 ! dbg
260 ! write(*,"(/A,I7)")' Deleting cluster: ',cluster%ID
261  CALL delete_particles_in_cluster(cluster)
262 
263  if(associated(cluster%next_cluster)) then
264  cluster_ll => cluster%next_cluster
265  else
266  NULLIFY(cluster_ll)
267  endif
268  cdeleted = cdeleted + 1
269  NULLIFY(cluster%next_cluster)
270  NULLIFY(cluster%PARTICLE_LL)
271  DEALLOCATE(cluster)
272  NULLIFY(cluster)
273  enddo
274 
275  if(cdeleted == clustercount) then
276 ! dbg
277 ! write(*,"(4X,A,I7)")'Number of clusters deleted: ',cDeleted
278  clustercount = 0
279  else
280  write(*,"()")' cDeleted /= ClusterCount'
281  CALL mfix_exit(mype)
282  endif
283 
284  endif
285 
286  END SUBROUTINE delete_clusters
287 
288 
289 
290 !......................................................................!
291 ! !
292 !......................................................................!
293  SUBROUTINE delete_particles_in_cluster(cluster)
295  TYPE(cluster_type), INTENT(INOUT), POINTER :: cluster
296 
297  TYPE(particle_type), POINTER :: particle
298  INTEGER pL, pDeleted
299 
300  NULLIFY(particle)
301  pdeleted = 0
302 
303  if(.NOT.associated(cluster%PARTICLE_LL) .AND. cluster%ParticleCount == 0) then
304  write(*,"(//,3x,A,//)") 'No particles to delete!'
305  elseif(.NOT.associated(cluster%PARTICLE_LL) .AND. cluster%ParticleCount /= 0) then
306  write(*,"(//,3x,A,//)") ' Error with ParticleCount and pointer - Er:1'
307  elseif(associated(cluster%PARTICLE_LL) .AND. cluster%ParticleCount == 0) then
308  write(*,"(//,3x,A,//)") ' Error with ParticleCount and pointer - Er:2'
309  else
310  do pl =1, cluster%ParticleCount
311  CALL getnextparticle(cluster, particle)
312 ! dbg
313 ! write(*,"(6X,A,I7)")' Deleting particle: ',particle%ID
314 
315  if(associated(particle%next_particle)) then
316  cluster%PARTICLE_LL => particle%next_particle
317  else
318  NULLIFY(cluster%PARTICLE_LL)
319  endif
320  pdeleted = pdeleted + 1
321  NULLIFY(particle%next_particle)
322  DEALLOCATE(particle)
323  NULLIFY(particle)
324  enddo
325 
326  if(pdeleted == cluster%ParticleCount) then
327 ! dbg
328 ! if(pDeleted >1 ) &
329 ! write(*,"(4X,A,I7)")'Number of deleted particles: ',&
330 ! pDeleted
331  cluster%ParticleCount = 0
332  else
333  write(*,"()")' pDeleted /= cluster%ParticleCount'
334  CALL mfix_exit(mype)
335  endif
336 
337  endif
338 
339 
340  END SUBROUTINE delete_particles_in_cluster
341 
342 
343 
344 !......................................................................!
345 ! !
346 !......................................................................!
347  SUBROUTINE add_particle_to_cluster(cluster, pID)
349  TYPE(cluster_type), INTENT(INOUT), POINTER :: cluster
350  INTEGER, INTENT(IN) :: pID
351 
352  type(particle_type), POINTER :: particle
353 
354 ! Create a particle instance.
355  ALLOCATE(particle)
356  NULLIFY(particle%next_particle)
357 ! Set the particle id.
358  particle%ID = pid
359 ! Set the cluster pointer to particle.
360  IF(cluster%ParticleCount == 0) THEN
361  cluster%ParticleCount = 1
362  cluster%PARTICLE_LL => particle
363  ELSE
364  cluster%ParticleCount = cluster%ParticleCount + 1
365  particle%next_particle => cluster%PARTICLE_LL
366  cluster%PARTICLE_LL => particle
367  ENDIF
368 
369 
370  END SUBROUTINE add_particle_to_cluster
371 
372 
373 !......................................................................!
374 ! !
375 !......................................................................!
376  SUBROUTINE getnextcluster(cluster)
378  TYPE(cluster_type), INTENT(INOUT), POINTER :: cluster
379 
380  if(.NOT.associated(cluster)) then
381 ! point cluster to first cluster in linked list of clusters
382  cluster => cluster_ll
383  elseif(associated(cluster%next_cluster)) then
384  cluster => cluster%next_cluster
385  else
386  print*,' You are looking for a cluster that does not exist'
387  CALL mfix_exit(mype)
388  endif
389  END SUBROUTINE getnextcluster
390 
391 
392 
393 !......................................................................!
394 ! !
395 !......................................................................!
396  SUBROUTINE getnextparticle(cluster, particle)
398  TYPE(cluster_type), INTENT(IN), POINTER :: cluster
399  TYPE(particle_type), INTENT(INOUT), POINTER :: particle
400 
401  if(.NOT.associated(particle)) then
402  particle => cluster%PARTICLE_LL
403  elseif(associated(particle%next_particle)) then
404  particle => particle%next_particle
405  else
406  print*,' You are looking for a particle that does not exist'
407  CALL mfix_exit(mype)
408  endif
409  END SUBROUTINE getnextparticle
410 
411 
412 
413 !......................................................................!
414 ! !
415 !......................................................................!
416  SUBROUTINE add_particle_to_psearchhistory(particle, pID)
418  TYPE(particle_type), INTENT(OUT), POINTER :: particle
419  INTEGER, INTENT(IN) :: pID
420 
421  ALLOCATE(particle)
422 
423  NULLIFY(particle%next_particle)
424 
425 !dbg
426 ! print *, '----------> addparticle_to_psearchhistory'
427 
428  if(psearchhistorycount == 0) then
429 ! no particles in search list have been created/identified
430  if(associated(psearch_history_ll)) then
431  print*, ' Error - particle history pointer already &
432  & associated!'
433  CALL mfix_exit(mype)
434  else
436  particle%ID = pid
437 ! create first particle of linked list of particles. with
438 ! psearch_history_ll always pointing to the 'first' in the list
439  psearch_history_ll => particle
440 ! dbg
441 ! write(*,"(/A,I7)") 'Create history w/ particle ', pID
442  endif
443  else
444  if(.NOT.associated(psearch_history_ll)) then
445  print*, ' Error - particle history pointer is not &
446  & associated!'
447  CALL mfix_exit(mype)
448  else
450  particle%ID = pid
451 ! establish the link between the new particle and existing particle list
452  particle%next_particle => psearch_history_ll
453 ! reassign/point psearch_history_ll to be 'first' in the linked list
454  psearch_history_ll => particle
455 ! as a result the linked list of particles is created from 'bottom-up'
456 ! with the new particle always being inserted before any existing
457 ! particles
458 ! dbg
459 ! print *, 'Add particle in history ', pID
460 
461  endif
462  ENDIF
463 
464  END SUBROUTINE add_particle_to_psearchhistory
465 
466 
467 
468 !......................................................................!
469 ! !
470 !......................................................................!
471  SUBROUTINE gettopparticle_in_psearchhistory(particle)
473  TYPE(particle_type), INTENT(INOUT), POINTER :: particle
474 
475 !dbg
476 ! print *, '----------> gettopparticle_in_psearchhistory'
477 
478  if(.NOT.associated(particle)) then
479 ! point particle to first particle in linked list of particles
480  particle => psearch_history_ll
481  elseif(associated(particle%next_particle)) then
482 ! this will never happen if we nullify particle at start of this
483 ! routine.
484  particle => particle%next_particle
485  else
486  print*,' You are looking for a particle that does not exist'
487  CALL mfix_exit(mype)
488  endif
489  END SUBROUTINE gettopparticle_in_psearchhistory
490 
491 
492 
493 !......................................................................!
494 ! !
495 !......................................................................!
498  TYPE(particle_type), POINTER :: particle
499 
500  NULLIFY(particle)
501 !dbg
502 ! print *, '----------> deletetopparticle_in_psearchhistory'
503 
504  if(.NOT.associated(psearch_history_ll) .AND. &
505  psearchhistorycount == 0) then
506  write(*,"(//,3x,A,//)") 'No particles in history to delete!'
507  elseif(.NOT.associated(psearch_history_ll) .AND. &
508  psearchhistorycount /= 0) then
509  write(*,"(//,3x,A,//)") &
510  ' Error with pSearchHistoryCount and pointer - Er:1'
511  elseif(associated(psearch_history_ll) .AND. &
512  psearchhistorycount == 0) then
513  write(*,"(//,3x,A,//)") &
514  ' Error with pSearchHistoryCount and pointer - Er:2'
515  else
516  CALL gettopparticle_in_psearchhistory(particle)
517 ! dbg
518 ! write(*,"(A,I7)")' Deleting particle: ',particle%ID
519 
520  if(associated(particle%next_particle)) then
521  psearch_history_ll => particle%next_particle
522  else
523  NULLIFY(psearch_history_ll)
524  endif
526  NULLIFY(particle%next_particle)
527  DEALLOCATE(particle)
528  NULLIFY(particle)
529 
530  if(psearchhistorycount < 0) then
531  write(*,"(4X,A)")'pSearchHistoryCount < 0'
532  CALL mfix_exit(mype)
533  endif
534 
535  endif
536 
538 
539 
540 
541 !......................................................................!
542 ! !
543 !......................................................................!
544  SUBROUTINE delete_psearchhistory()
546  TYPE(particle_type), POINTER :: particle
547  INTEGER pL, pDeleted
548 
549  NULLIFY(particle)
550  pdeleted = 0
551 !dbg
552 ! print *, '----------> delete_psearch_history'
553 
554  if(.NOT.associated(psearch_history_ll) .AND. &
555  psearchhistorycount == 0) then
556 ! dbg
557 ! write(*,"(//,3x,A,//)") 'No particles in history to delete!'
558  elseif(.NOT.associated(psearch_history_ll) .AND. &
559  psearchhistorycount /= 0) then
560  write(*,"(//,3x,A,//)") &
561  ' Error with pSearchHistoryCount and pointer - Er:1'
562  elseif(associated(psearch_history_ll) .AND. &
563  psearchhistorycount == 0) then
564  write(*,"(//,3x,A,//)") &
565  ' Error with pSearchHistoryCount and pointer - Er:2'
566  else
567  do pl =1, psearchhistorycount
568 
569  CALL gettopparticle_in_psearchhistory(particle)
570 ! dbg
571 ! write(*,"(/A,I7)")' Deleting particle: ',particle%ID
572 
573  if(associated(particle%next_particle)) then
574  psearch_history_ll => particle%next_particle
575  else
576  NULLIFY(psearch_history_ll)
577  endif
578  pdeleted = pdeleted + 1
579  NULLIFY(particle%next_particle)
580  DEALLOCATE(particle)
581  NULLIFY(particle)
582  enddo
583 
584  if(pdeleted == psearchhistorycount) then
585 ! dbg
586 ! write(*,"(4X,A,I7)")'Number of particles deleted: ',pDeleted
588  else
589  write(*,"()")' pDeleted /= PSearchHistoryCount'
590  CALL mfix_exit(mype)
591  endif
592 
593  endif
594 
595  END SUBROUTINE delete_psearchhistory
596 
597 
598 
599 !......................................................................!
600 ! !
601 !......................................................................!
602  SUBROUTINE print_clusters
604  use run
605 
606  implicit none
607 
608 ! Generic loop counters
609  integer lc1, lc2, lc3, lc4
610 ! Particle index (mapped to cluster send/recv)
611  integer L
612 
613 ! Flags used for debugging.
614 ! 0: No messages
615 ! 1: Screen only messages
616 ! 2: Detailed Files are written by each process
617  INTEGER, parameter :: dbg_level = 0
618 
619 ! Particle properties (for cluster bound particles only)
620  double precision, dimension(:), allocatable :: lRad
621  double precision, dimension(:,:), allocatable :: lPos
622  double precision, dimension(:,:), allocatable :: lVel_s
623 
624 ! File properticles (for cluster bound particles only)
625  double precision, dimension(:), allocatable :: lEpg
626  double precision, dimension(:), allocatable :: lRog
627  double precision, dimension(:), allocatable :: lMug
628  double precision, dimension(:,:), allocatable :: lVel_g
629 
630 ! An array for post process data storage.
631  double precision, dimension(:), allocatable :: lPost
632 
633 ! Cluster analysis variables:
634  integer lMin(1:3), lMax(1:3)
635 
636  double precision avgEpg, avgRe, avgSlip, lSlip
637  double precision avgVel_s(1:3), avgVel_g(1:3)
638 
639  double precision posMin(1:3), posMax(1:3)
640  double precision clSize(1:3), clDiameter
641 
642  double precision cSize
643 
644  Type(ctype), pointer :: cThis
645  Type(ptype), pointer :: pThis
646 
647 ! Merge cluster data from all processes and set up send/recv datav.
648  call init_print_clusters(dbg_level)
649 
650 ! Get particle data from all processes. Only collect what is needed.
651  call getclusterparticledata(des_radius, lrad) ! Radius
652  call getclusterparticledata(des_pos_new, lpos) ! Position
653  call getclusterparticledata(des_vel_new, lvel_s) ! Velocity
654 
655 ! Get field variable data from all processes.
656  call getclusterfielddata(ep_g, lepg)
657  call getclusterfielddata(ro_g, lrog)
658  call getclusterfielddata(mu_g, lmug)
659  call getclusterfielddata(u_g, v_g, w_g, lvel_g)
660 
661 ! Allocate output data variable. (Root process only.) This data must
662 ! be sent back to the individual processes.
663  allocate(lpost( recv_sum)); lpost = zero
664 ! Initialize the global storage variable.
665  postcluster = zero
666 
667 ! Calculate and report cluster stats.
668  if(mype == clusterpe) then
669  open (unit=203, file='clusterInfo.dat', &
670  status='unknown', position='append')
671  if(clustercount_all == 0) then
672  write(203,"(/3X,'Time: ',F9.6,3x,'No clusters to print.')")&
673  time
674  else
675  write(203,"(/3X,'Time: ',F9.6)") time
676 
677  nullify(cthis)
678  nullify(pthis)
679  lc2 = 0
680  lp_lc10: do lc1 = 1, clustercount_all
681 ! Only clusters with more than 3 particles are processed. Keep track of
682 ! the number reported vs. number processed.
683  if(clusters(lc1)%size < 4) cycle lp_lc10
684  lc2 = lc2 + 1
685 
686 ! Initialize variables.
687  avgepg = zero
688  avgvel_g = zero
689  avgvel_s = zero
690  avgre = zero
691 
692  posmin = large_number; lmin = 0
693  posmax = zero; lmax = 0
694 
695 ! Loop over particles comprising this cluster.
696  lc3 = 0
697  cthis => clusters(lc1)
698  if(associated(cthis%particle)) then
699  pthis => cthis%particle
700  else
701  nullify(pthis)
702  endif
703 ! Although this loop could be based on the cluster size, it is safer
704 ! to loop through the link-list. If there was an allocation error, this
705 ! should prevent the code from crashing.
706  do while(associated(pthis))
707  lc3 = lc3 + 1
708 ! Get the particle map index. This index is used to get data from the
709 ! send/recv variables.
710  l = pthis%map
711 
712 ! Report a problem if viscosity is zero. (sanity check)
713  if(lmug(l) == zero) then
714  write(*,"(3x,'Invalid Mu_g. ', &
715  &'Omitting cluster data: ',I4)") lc1
716  lc2 = lc2 - 1
717  cycle lp_lc10
718  endif
719 
720  lslip = zero
721  do lc4=1, merge(2, 3, no_k)
722 ! Calculate the cluster's dimensions:
723  if((lpos(l,lc4)-lrad(l)) < posmin(lc4)) then
724  posmin(lc4) = lpos(l,lc4)-lrad(l)
725  lmin(lc4) = l
726  endif
727  if((lpos(l,lc4)+lrad(l)) > posmax(lc4)) then
728  posmax(lc4) = lpos(l,lc4)+lrad(l)
729  lmax(lc4) = l
730  endif
731 ! Calculate the slip velocity.
732  lslip = lslip + (lvel_g(l,lc4)-lvel_s(l,lc4))**2
733  enddo
734  lslip = dsqrt(lslip)
735 
736 ! This is a sanity check on the data. Although a zero slip velocity is
737 ! possible, (hopefully) there is always some small variance.
738  if(lslip == zero) then
739  write(*,"(3x,'Invalid lSlip. ', &
740  &'Omitting cluster data: ',I4)") lc1
741  lc2 = lc2 - 1
742  cycle lp_lc10
743  endif
744 
745  avgvel_s = avgvel_s + lvel_s(l,:)
746  avgvel_g = avgvel_g + lvel_g(l,:)
747  avgepg = avgepg + lepg(l)
748  avgre = avgre + lrog(l)*lepg(l)*lslip*2.0d0*lrad(l)/lmug(l)
749 
750 ! Store the cluster size with the particle. (Output data in vtk files.)
751  lpost(l) = float(cthis%size)
752 
753 ! Increment the loop.
754  if(associated(pthis%next)) then
755  pthis => pthis%next
756  else
757  nullify(pthis)
758  endif
759  enddo
760 ! This is where the above loop is checked against the previously
761 ! calculated cluster size. They should match.
762  if(lc3 /= cthis%size) then
763  write(*,"(3x,'Error processing particles. ', &
764  &'Omitting cluster data: ',I4)") lc1
765  lc2 = lc2 - 1
766  cycle lp_lc10
767  endif
768 
769  csize = dble(cthis%size)
770  avgepg = avgepg / csize
771  avgvel_g = avgvel_g / csize
772  avgvel_s = avgvel_s / csize
773  avgre = avgre / csize
774 
775  avgslip = zero
776  clsize = zero
777  do lc4=1, merge(2, 3, no_k)
778  avgslip = avgslip + (avgvel_g(lc4)-avgvel_s(lc4))**2
779  clsize(lc4) = posmax(lc4) - posmin(lc4)
780  enddo
781  avgslip = dsqrt(avgslip)
782 
783 ! Cluster diameter is calculated by using an equivalent circle diameter
784 ! of an ellipse in each plane. Then weighting this area by the slip
785 ! velocity normal to it. This in effect gives a hydrodynamic diameter
786 ! of the cluster.- 1660
787  if(do_k) then
788  cldiameter = &
789  clsize(2)*clsize(3)*(avgvel_g(1)-avgvel_s(1))**2 &
790  + clsize(1)*clsize(3)*(avgvel_g(2)-avgvel_s(2))**2 &
791  + clsize(1)*clsize(2)*(avgvel_g(3)-avgvel_s(3))**2
792 
793  cldiameter = dsqrt(cldiameter) / avgslip
794  else
795  cldiameter = undefined
796  endif
797 
798  write(203,"(4X,I7,4X,I7,4(1X,G13.6))") lc1, &
799  cthis%size, avgepg, avgre, avgslip, cldiameter
800 
801  enddo lp_lc10
802 
803  write(203,"(4X,'Clusters reported: ', I7, &
804  &4x,'Clusters processed: ', I7)") clustercount_all, lc2
805  endif
806  close(203)
807  endif
808 
809  call sendclusterdata(lpost, postcluster)
810 
811  nullify(cthis)
812  nullify(pthis)
813 
814  if(allocated(lrad)) deallocate(lrad)
815  if(allocated(lpos)) deallocate(lpos)
816  if(allocated(lvel_s)) deallocate(lvel_s)
817 
818  if(allocated(lepg)) deallocate(lepg)
819  if(allocated(lrog)) deallocate(lrog)
820  if(allocated(lmug)) deallocate(lmug)
821  if(allocated(lvel_g)) deallocate(lvel_g)
822 
823  if(allocated(lpost)) deallocate(lpost)
824 
825  call finl_print_clusters(dbg_level)
826 
827  END SUBROUTINE print_clusters
828 
829 
830 !......................................................................!
831 ! Module name: INIT_PRINT_CLUSTERS !
832 ! !
833 ! Purpose: Collect cluster information from all process on root. !
834 ! > Number of clusters on each process. !
835 ! > Number of particles in each cluster. !
836 ! !
837 ! This information is used to construct a send/receive map for !
838 ! cluster data. !
839 ! !
840 ! Author: J.Musser Date: Dec-12 !
841 !......................................................................!
842  SUBROUTINE init_print_clusters(dbg_level)
844  use run
845 
846  implicit none
847 
848 ! Flags used for debugging.
849 ! 0: No messages
850 ! 1: Screen only messages
851 ! 2: Detailed Files are written by each process
852  INTEGER, intent(in) :: dbg_level
853 
854 
855 ! Counter of processes
856  INTEGER proc, ierr
857 ! Generic loop counters
858  INTEGER lc1, lc2, lc3, lc4
859 
860  character(LEN=255) :: filename
861 
862 ! Local process data:
863 !----------------------->>
864 
865  TYPE(cluster_type), POINTER :: cluster
866  TYPE(particle_type), POINTER :: particle
867 
868 ! Number of partcies in each cluster on local process.
869  INTEGER, dimension(:), allocatable :: pCnt
870 ! Number of clusters on local process.
871  INTEGER, dimension(:) :: cCnt(0:numpes-1)
872 ! Global IDs of particles in clusters (array)
873  INTEGER, dimension(:), allocatable :: gpIDs
874 ! IS_GHOST entries for particles in clusters. (array)
875  LOGICAL, dimension(:), allocatable :: gpGhost
876 
877 ! Root process data:
878 !----------------------->>
879 
880 ! The number of clusters detected on each process.
881  INTEGER, dimension(:) :: cCnt_all(0:numpes-1)
882 ! Sum of cCnt_all entries
883  INTEGER cCnt_sum
884 
885 ! The number of particles in each cluster.
886  INTEGER, dimension(:), allocatable :: pCnt_all
887 
888 ! Displacements used for send/receive and cluster mapping.
889  INTEGER, dimension(:) :: pCnt_dsp(0:numpes-1)
890 
891  INTEGER, dimension(:), allocatable :: gp_dsp
892 
893 ! Global IDs of particles in clusters (array)
894  INTEGER, dimension(:), allocatable :: gpIDs_all
895 ! Ghost entries for particles in clusters. (array)
896  LOGICAL, dimension(:), allocatable :: gpGhost_all
897 
898  INTEGER, dimension(:,:), allocatable :: mergeMap
899  LOGICAL merging
900 
901  Type(ctype), pointer :: this
902 
903  call des_mpi_barrier()
904 
905  if(mype == clusterpe .and. dbg_level >=1) &
906  write(*,"(//1x,'Start data dump ',50('-'),'>'/)")
907 
908  if(dbg_level >= 2) then
909  filename=''
910  write(filename,"('dbg_check_',I2.2,'.txt')")mype
911  open(convert='big_endian',unit=202, file=filename, &
912  status='replace', position='append')
913  write(202,"(3x,'check A')")
914  endif
915 
916 ! Allocate receive buffer and receive count arrays.
917  allocate( recv_cnt(0:numpes-1) )
918  allocate( recv_dsp(0:numpes-1) )
919 
920 ! Set the gather counts array.
921  ccnt = 0; ccnt_all = 0
922  ccnt(mype) = clustercount
923  call global_sum(ccnt ,ccnt_all)
924  call des_mpi_barrier()
925  if(dbg_level >= 1) call dbg_print_clusters(1)
926  if(dbg_level >= 2) write(202,"(5x,'check 1')")
927 
928 ! Create an array identifying the number of particles in each cluster.
929  allocate(pcnt(ccnt(mype)))
930  NULLIFY(cluster)
931  do lc1 = 1, ccnt(mype)
932  CALL getnextcluster(cluster)
933  pcnt(lc1) = cluster%ParticleCount
934  enddo
935  if(dbg_level >= 2) then
936  call dbg_print_clusters(2)
937  write(202,"(5x,'check 2')")
938  endif
939 
940 ! Calculate the total number of clusters in the entire domain.
941  ccnt_sum = 1
942  if(mype == clusterpe) ccnt_sum = sum(ccnt_all)
943 
944 ! Allocate an array sized to the total number of clusters in the
945 ! entire domain.
946  allocate(pcnt_all(ccnt_sum)); pcnt_all(:) = 1
947  if(mype == clusterpe) then
948  pcnt_dsp(0) = 0
949 ! Calculate the array displacement for MPI_GATHER
950  do proc = 1,numpes-1
951  pcnt_dsp(proc) = pcnt_dsp(proc-1) + ccnt_all(proc-1)
952  enddo
953  endif
954  if(dbg_level >= 2) then
955  call dbg_print_clusters(3)
956  write(202,"(5x,'check 3')")
957  endif
958 
959 ! Populate pCnt_all on clusterPE.
960  call des_mpi_gatherv(pcnt, ccnt(mype), pcnt_all, ccnt_all, &
961  pcnt_dsp, clusterpe, ierr)
962  if(dbg_level >= 1) call dbg_print_clusters(4)
963  if(dbg_level >= 2) write(202,"(5x,'check 4')")
964  call des_mpi_barrier()
965 
966 
967  send_cnt = sum(pcnt)
968  if(mype == clusterpe) then
969  recv_cnt(:) = 0
970  do proc = 0, numpes-1
971  if(ccnt_all(proc) > 0) then
972  do lc1=1, ccnt_all(proc)
973  recv_cnt(proc) = recv_cnt(proc) + &
974  pcnt_all(lc1 + pcnt_dsp(proc))
975  enddo
976  else
977  recv_cnt(proc) = 0
978  endif
979  enddo
980  recv_dsp(:) = 0
981  do proc = 1, numpes-1
982  recv_dsp(proc) = recv_dsp(proc-1) + recv_cnt(proc-1)
983  enddo
984  recv_sum = sum(recv_cnt)
985  else
986  recv_sum = 1
987  endif
988  if(dbg_level >= 1) call dbg_print_clusters(5)
989  if(dbg_level >= 2) write(202,"(5x,'check 5')")
990 
991 
992  allocate( gp_dsp(ccnt_sum) ); gp_dsp(:) = 0
993  if(mype == clusterpe) then
994  do lc1 = 2, ccnt_sum
995  gp_dsp(lc1) = gp_dsp(lc1-1) + pcnt_all(lc1-1)
996  enddo
997  endif
998  if(dbg_level >= 1) call dbg_print_clusters(6)
999  if(dbg_level >= 2) write(202,"(5x,'check 6')")
1000 
1001 
1002 ! Transfer global particle IDs:
1003  call getclusterparticledata(iglobal_id, gpids_all, gpids)
1004  if(dbg_level >= 2) then
1005  call dbg_print_clusters(7)
1006  write(202,"(5x,'check 7')")
1007  endif
1008 
1009 
1010 ! Transfer particle ghost array:
1011  call getclusterghostdata(gpghost_all, gpghost)
1012  if(dbg_level >= 2) then
1013  call dbg_print_clusters(7)
1014  write(202,"(5x,'check 7')")
1015  call dbg_print_clusters(9)
1016  write(202,"(5x,'check 9')")
1017  call dbg_print_clusters(10)
1018  write(202,"(5x,'check 10')")
1019  call dbg_print_clusters(11)
1020  write(202,"(5x,'check 11')")
1021  elseif(dbg_level >= 1) then
1022  call dbg_print_clusters(11)
1023  endif
1024 
1025 
1026  if(mype == clusterpe) then
1027 ! If there are two or more clusters, check to see if there is any of
1028 ! the clusters intersect. (Merge clusters that span multiple processes.)
1029  if( ccnt_sum > 1) then
1030  allocate(mergemap(ccnt_sum, ccnt_sum)); mergemap = 0
1031  do lc1 = 1, ccnt_sum
1032  mergemap(lc1,lc1) = 1
1033  enddo
1034 ! Loop over clusters, comparing the global IDs of the particles that
1035 ! they contain. Any clusters with overlapping particles are later
1036 ! merged as a single cluster.
1037  lp_lc1: do lc1 = 1, ccnt_sum-1
1038  lp_lc2: do lc2 = 1+gp_dsp(lc1), gp_dsp(lc1)+pcnt_all(lc1)
1039  lp_lc3: do lc3 = lc1+1, ccnt_sum
1040  lp_lc4: do lc4 = 1+gp_dsp(lc3), gp_dsp(lc3)+pcnt_all(lc3)
1041  if(gpids_all(lc2) == gpids_all(lc4)) then
1042  mergemap(lc1,lc3) = 1
1043  mergemap(lc3,lc1) = 1
1044  if(dbg_level >= 1) &
1045  write(*,"(3x,'Merge: ',I5,' and ',I5)") lc1, lc3
1046  endif
1047  enddo lp_lc4
1048  enddo lp_lc3
1049  enddo lp_lc2
1050  enddo lp_lc1
1051  if(dbg_level >= 1) then
1052  write(*,*)''
1053  call dbg_print_clusters(8, lmsg='before')
1054  endif
1055 
1056 ! Merge any clusters that share common particles. Common particles are
1057 ! identified by their global particle IDs. Note that if two processes
1058 ! contain a common particle, the particle should be 'real' on one
1059 ! process and a ghost on the other.
1060  merging = .true.
1061  do while(merging)
1062  merging = .false.
1063  lp_lc11: do lc1=1,ccnt_sum-1
1064  if(sum(mergemap(lc1,:)) == 0) cycle lp_lc11
1065  lp_lc21: do lc2=lc1+1,ccnt_sum
1066  if(mergemap(lc1,lc2) /= 1) cycle lp_lc21
1067  lc3=lc2
1068  lp_lc41: do lc4 = 1, ccnt_sum
1069  if(lc3 == lc4) cycle lp_lc41
1070  if(mergemap(lc3,lc4) == 1) then
1071  mergemap(lc1,lc4) = 1
1072  mergemap(lc3,lc4) = 0
1073  mergemap(lc3,lc3) = 0
1074  merging = .true.
1075  endif
1076  enddo lp_lc41
1077  enddo lp_lc21
1078  enddo lp_lc11
1079  enddo
1080  if(dbg_level >= 1) &
1081  call dbg_print_clusters(8, lmsg='after')
1082 
1083 ! Count the actual number of clusters in the domain.
1084  clustercount_all = 0
1085  do lc1=1,ccnt_sum
1086  if(sum(mergemap(lc1,:)) > 0) then
1088  endif
1089  enddo
1090  if(dbg_level >= 1) then
1091  write(*,"(3x,'Number of clusters reported by ', &
1092  &'all processes: ',I6)") ccnt_sum
1093  write(*,"(3x,'Actual number of clusters: ',I6)") &
1095  write(*,*)''
1096  endif
1097 
1098 
1099 ! Allocate the clusters pointer array. This array is populated with
1100 ! data used to map particles to send/recv data. Ghost particles are not
1101 ! included in the map so that cluster analysis only contains data from
1102 ! real particles.
1103  allocate(clusters(clustercount_all))
1104  do lc1=1,clustercount_all
1105  nullify(clusters(lc1)%particle)
1106  clusters(lc1)%size = 0
1107  enddo
1108  lc3 = 0
1109  lp_lc12: do lc1=1, ccnt_sum
1110  if(sum(mergemap(lc1,:)) == 0) cycle lp_lc12
1111  lc3 = lc3 + 1
1112  this => clusters(lc3); this%size = 0
1113  lp_lc22: do lc2=1, ccnt_sum
1114  if(mergemap(lc1,lc2) == 0) cycle lp_lc22
1115  lp_lc42: do lc4=1+gp_dsp(lc2),gp_dsp(lc2)+pcnt_all(lc2)
1116  if(gpghost_all(lc4)) cycle lp_lc42
1117  call addparticle(this, lc4, gpids_all(lc4))
1118  enddo lp_lc42
1119  enddo lp_lc22
1120  enddo lp_lc12
1121  deallocate(mergemap)
1122  if(dbg_level >= 1) &
1123  call dbg_print_clusters(12, dbg=dbg_level)
1124 
1125 ! If there is only one cluster, there is no need to check for
1126 ! intersecting clusters.
1127  elseif( ccnt_sum == 1) then
1128  if(dbg_level >= 1) &
1129  write(*,"(3x,'Just one cluster: No merge.',/)")
1130  clustercount_all = 1
1131  allocate(clusters(clustercount_all))
1132  nullify(clusters(clustercount_all)%particle)
1133  clusters(clustercount_all)%size = 0
1134  this => clusters(clustercount_all); this%size = 0
1135  do lc1=1, pcnt_all(1)
1136  if(gpghost_all(lc1)) write(*,"(3x, &
1137  &'Error: Ghost particle detected: ',I7)") lc1
1138  call addparticle(this, lc1, gpids_all(lc1))
1139  enddo
1140  if(dbg_level >= 1) &
1141  call dbg_print_clusters(12, dbg=dbg_level)
1142  else
1143  if(dbg_level >= 1) write(*,"(3x,'No clusters to merge.')")
1144  clustercount_all = 0
1145  allocate(clusters(1))
1146  nullify(clusters(1)%particle)
1147  clusters(1)%size = 0
1148  endif
1149  else
1150  clustercount_all = 0
1151  allocate( clusters(1) )
1152  nullify(clusters(1)%particle)
1153  clusters(1)%size = 0
1154  endif
1155  call des_mpi_barrier()
1156 
1157 ! clean up before returning.
1158  nullify(cluster)
1159  nullify(particle)
1160 
1161  if(allocated(pcnt)) deallocate(pcnt)
1162  if(allocated(gpids)) deallocate(gpids)
1163  if(allocated(gpghost)) deallocate(gpghost)
1164 
1165  if(allocated(pcnt_all)) deallocate(pcnt_all)
1166  if(allocated(gpids_all)) deallocate(gpids_all)
1167  if(allocated(gpghost_all)) deallocate(gpghost_all)
1168 
1169  if(allocated(gp_dsp)) deallocate(gp_dsp)
1170 
1171  return
1172 
1173  contains
1174 
1175 !......................................................................!
1176 ! Module name: dbg_PRINT_CLUSTERS !
1177 ! !
1178 ! Purpose: A collection of various write statements for debugging. !
1179 ! !
1180 ! Author: J.Musser Date: Dec-12 !
1181 !......................................................................!
1182  SUBROUTINE dbg_print_clusters(lmsgID, lmsg, dbg)
1183  use run
1184 
1185  implicit none
1186 
1187 ! Index for printing a specific message.
1188  INTEGER, INTENT(IN) :: lmsgID
1189 
1190 ! A message to write with data.
1191  CHARACTER(len=*), intent(in), optional :: lmsg
1192 
1193  INTEGER, INTENT(IN), optional :: dbg
1194 
1195 ! Generic loop counters
1196  INTEGER proc, lc1, lc2, lc3, lc4
1197 ! Generic write buffers.
1198  CHARACTER(len=120) wbuff, wbuff2
1199 ! String for generating filenames.
1200  CHARACTER(LEN=255) :: filename
1201 
1202 ! Generic cluster pointer.
1203  Type(ctype), pointer :: cThis
1204 ! Generic cluster pointer.
1205  Type(ptype), pointer :: pThis
1206 
1207  SELECT CASE(lmsgid)
1208 
1209 !``````````````````````````````````````````````````````````````````````!
1210 ! Root Process Only - !
1211 ! !
1212 ! Purpose:: Message to write out the number of clusters detected on !
1213 ! each process. !
1214 ! !
1215 !``````````````````````````````````````````````````````````````````````!
1216  CASE (1); if(mype /= clusterpe) return
1217 
1218  do proc=0,numpes-1
1219  write(*,"(3x,'Process ',I2,' reporting ',I4,' clusters.')") &
1220  proc, ccnt_all(proc)
1221  enddo
1222  write(*,"(3x,'Total reported clusters: ',I6)") sum(ccnt_all)
1223  write(*,*)''
1224 
1225 
1226 !``````````````````````````````````````````````````````````````````````!
1227 ! All Processes - !
1228 ! !
1229 ! Purpose:: Each process creates a file and records the particles !
1230 ! contained in clusters. Only the data from the current pass is kept !
1231 ! (file status='replace'). !
1232 ! !
1233 !``````````````````````````````````````````````````````````````````````!
1234  CASE (2) ! All processes
1235 
1236  filename = ''
1237  write(filename,"('dbg_pCnt_',I2.2,'.txt')") mype
1238  open(convert='big_endian',unit=201, file=filename, status='replace')
1239  write(201,"(//3x,'Time:',F18.6)")time
1240  write(201,"(3x,'Number of Clusters: ',I4)") ccnt(mype)
1241 
1242  if(ccnt(mype) > 0) then
1243  nullify(cluster)
1244  do lc2 = 1, clustercount
1245  write(201,"(3x,'/Cluster ',I5,' has ',I8,' members.')")
1246  write(201,"(5x,'Membership:')")
1247  CALL getnextcluster(cluster)
1248  NULLIFY(particle)
1249  do lc1 = 1, cluster%ParticleCount
1250  CALL getnextparticle(cluster, particle)
1251  write(201,"(5x,'Global ID: ',I8)") &
1252  iglobal_id(particle%ID)
1253  enddo
1254  enddo
1255  endif
1256  close(201)
1257 
1258 
1259 !``````````````````````````````````````````````````````````````````````!
1260 ! Root Process Only - !
1261 ! !
1262 ! Purpose:: Root process constructs a file that lists all the particle !
1263 ! from all processes that are contained in clusters. Only data from !
1264 ! the current pass is kept (file status='replace'). !
1265 ! !
1266 !``````````````````````````````````````````````````````````````````````!
1267  CASE (3); if(mype /= clusterpe) return
1268 
1269  filename = 'dbg_pCnt_dsp.txt'
1270  open(convert='big_endian',unit=201, file=filename, status='replace')
1271  write(201,"(/3x,'Time:',F18.6)")time
1272  write(201,"(3x,'cCnt_sum: ',I4)") ccnt_sum
1273  do lc1 =0, numpes-1
1274  write(201,"(5x,'pCnt_dsp(',I4,'): ',I6)")lc1, pcnt_dsp(lc1)
1275  enddo
1276  close(201)
1277 
1278 
1279 !``````````````````````````````````````````````````````````````````````!
1280 ! Root Process Only - !
1281 ! !
1282 ! Purpose:: Root process reports the number of clusters on each !
1283 ! process and the number of particles comprising each cluster. !
1284 ! !
1285 !``````````````````````````````````````````````````````````````````````!
1286  CASE (4); if(mype /= clusterpe) return
1287 
1288  if(ccnt_sum > 0)then
1289  write(*,"(3x,'Total number of clusters: ',I6)") ccnt_sum
1290  do proc = 0, numpes-1
1291  if(ccnt_all(proc) > 0) then
1292  write(*,"(5x,'Process ',I2,': cluster count: ',I4)") &
1293  proc, ccnt_all(proc)
1294  do lc1 = 1, ccnt_all(proc)
1295  write(*,"(7x,'Particles in cluster ',I4,': ',I6)")&
1296  lc1, pcnt_all(lc1 + pcnt_dsp(proc))
1297  enddo
1298  else
1299  write(*,"(3x,'Process ',I2,' reports no clusters.')")&
1300  proc
1301  endif
1302  enddo
1303  write(*,*)''
1304  endif
1305 
1306 
1307 !``````````````````````````````````````````````````````````````````````!
1308 ! Root Process Only - !
1309 ! !
1310 ! Purpose:: Root process reports the information on the send/recv !
1311 ! process for cluster_gather routines. !
1312 ! !
1313 !``````````````````````````````````````````````````````````````````````!
1314  CASE (5); if(mype /= clusterpe) return
1315 
1316  if(recv_sum > 0)then
1317  write(*,"(3x,'send_cnt: ',I8)") send_cnt
1318  write(*,"(3x,'recv_sum: ',I8)") recv_sum
1319  write(*,"(3x,'Generic send/recv setup:')")
1320  do proc = 0, numpes-1
1321  if(recv_cnt(proc) > 0) then
1322  write(*,"(5x,'Process ',I2,': count: ',I6,&
1323  &' disp:',I6)") &
1324  proc, recv_cnt(proc), recv_dsp(proc)
1325  else
1326  write(*,"(3x,'Process ',I2,' is empty.')") proc
1327  endif
1328  enddo
1329  else
1330  write(*,"(3x,'No data to send/recv.')")
1331  endif
1332  write(*,*)''
1333 
1334 
1335 !``````````````````````````````````````````````````````````````````````!
1336 ! Root Process Only - !
1337 ! !
1338 ! Purpose:: Root process reports the displacements for particle data !
1339 ! stored in the receive buffer for cluster_gather. !
1340 ! !
1341 !``````````````````````````````````````````````````````````````````````!
1342  CASE (6); if(mype /= clusterpe) return
1343 
1344  if(ccnt_sum > 0)then
1345  write(*,"(3x,'Global cluster-to-particle offset:')")
1346  do lc1 = 1, ccnt_sum
1347  write(*,"(7x,' Cluster ',I4,': ',I6)") &
1348  lc1, gp_dsp(lc1)
1349  enddo
1350  write(*,*)''
1351  endif
1352 
1353 
1354 !``````````````````````````````````````````````````````````````````````!
1355 ! Root Process Only - !
1356 ! !
1357 ! Purpose:: Root process constructs a file containing the global IDs !
1358 ! of all particles contained in clusters. !
1359 ! !
1360 !``````````````````````````````````````````````````````````````````````!
1361  CASE (7); if(mype /= clusterpe) return
1362 
1363  open(convert='big_endian',unit=201, file='dbg_gpIDs.txt', status='replace')
1364  do lc1=1,size(gpids_all)
1365  write(201,"(5x,' Global particle ID: ',I8)") gpids_all(lc1)
1366  enddo
1367 
1368  close(201)
1369 
1370 
1371 !``````````````````````````````````````````````````````````````````````!
1372 ! Root Process Only - !
1373 ! !
1374 ! Purpose:: Root process reports cluster merging data. Output is based !
1375 ! on the array data set in call to this routine. !
1376 ! !
1377 !``````````````````````````````````````````````````````````````````````!
1378  CASE (8); if(mype /= clusterpe) return
1379 
1380  if(.not.present(lmsg)) then
1381  write(*,"(/3x,'Invalid use of case debug report.')")
1382  return
1383  endif
1384 
1385  filename = ''
1386  write(filename,"('dbg_mergeMap_',A,I2.2,'.txt')") trim(lmsg)
1387  open(convert='big_endian',unit=201, file=filename, status='replace')
1388 
1389  write(201,"(/3x,'Time:',F18.6)")time
1390 
1391  lc1 = size(mergemap(:,1)) ! rows
1392  lc2 = min(size(mergemap(1,:)),25) ! columns
1393 
1394  wbuff = ''
1395  write(wbuff,"(7x,'1')")
1396  do lc3=2,lc2
1397  write(wbuff,"(A,3x,I1)") trim(wbuff), lc3
1398  enddo
1399 
1400  wbuff2 = ''
1401  write(wbuff2,"(5x,'|')")
1402  do lc3=1,lc2
1403  write(wbuff2,"(2A)") trim(wbuff2),'---|'
1404  enddo
1405 
1406  write(201,*)trim(wbuff)
1407  write(201,*)trim(wbuff2)
1408 
1409  do lc3=1,lc1
1410  wbuff = ''
1411  write(wbuff,"(3X,I1,' |')") lc3
1412  do lc4 = 1, lc2
1413  write(wbuff,"(A,1x,I1,' |')") &
1414  trim(wbuff), mergemap(lc3,lc4)
1415  enddo
1416  write(201,*)trim(wbuff)
1417  write(201,*)trim(wbuff2)
1418  enddo
1419  close(201)
1420 
1421 
1422 !``````````````````````````````````````````````````````````````````````!
1423 ! All Processes - !
1424 ! !
1425 ! Purpose:: Each process constructs a file and records ghost particle !
1426 ! information. !
1427 ! !
1428 !``````````````````````````````````````````````````````````````````````!
1429  CASE (9) ! All processes
1430 
1431  filename = ''
1432  write(filename,"('dbg_isghost_',I2.2,'.txt')") mype
1433  open(convert='big_endian',unit=201, file=filename, status='replace')
1434  write(201,"(/3x,'Time:',F18.6)")time
1435  do lc1 =1, send_cnt
1436  write(201,"(5x,'IS_GHOST(',I8,'): ',L2)")lc1, gpghost(lc1)
1437  enddo
1438  close(201)
1439 
1440 
1441 !``````````````````````````````````````````````````````````````````````!
1442 ! Root Process Only - !
1443 ! !
1444 ! Purpose:: Root process constructs a file and records ghost particle !
1445 ! information for all particles contained in clusters. !
1446 ! !
1447 !``````````````````````````````````````````````````````````````````````!
1448  CASE (10); if(mype /= clusterpe) return
1449 
1450  open(convert='big_endian',unit=201, file='dbg_isghost_all.txt', status='replace')
1451  write(201,"(/3x,'Time:',F18.6)")time
1452  do lc1 =1, recv_sum
1453  write(201,"(5x,'IS_GHOST(',I8,'): ',L2)")lc1, gpghost_all(lc1)
1454  enddo
1455  close(201)
1456 
1457 
1458 !``````````````````````````````````````````````````````````````````````!
1459 ! Root Process Only - !
1460 ! !
1461 ! Purpose:: Root process reports particles in clusters that are !
1462 ! identified as ghost particles on a process. !
1463 ! !
1464 !``````````````````````````````````````````````````````````````````````!
1465  CASE (11); if(mype /= clusterpe) return
1466 
1467  if(recv_sum <= 0) return
1468 
1469  lc2 = 0
1470  do proc = 0, numpes-1
1471  do lc1 = 1, ccnt_all(proc)
1472  lc2 = lc2 + 1
1473  do lc3 = 1, pcnt_all(lc2)
1474  if(gpghost_all(gp_dsp(lc2) + lc3)) then
1475  write(*,"(3x,'Particle ',I8,' in cluster ',I6, &
1476  &' is a ghost on process ',I2,'.')") &
1477  gpids_all(gp_dsp(lc2) + lc3), lc2, proc
1478  endif
1479  enddo
1480  enddo
1481  enddo
1482  write(*,*)''
1483 
1484 
1485 !``````````````````````````````````````````````````````````````````````!
1486 ! Root Process Only - !
1487 ! !
1488 ! Purpose:: Root process reports cluster statistics. !
1489 ! !
1490 !``````````````````````````````````````````````````````````````````````!
1491  CASE (12); if(mype /= clusterpe) return
1492 
1493  if(.not.present(dbg)) return
1494 
1495  if(dbg >= 1) then
1496  do lc1=1, clustercount_all
1497  write(*,"(3x,'Cluster ',I6,' reports ',I6,&
1498  &' particles.')") lc1, clusters(lc1)%size
1499  enddo
1500  endif
1501 
1502  if(dbg >= 2) then
1503  do lc1=1, clustercount_all
1504  filename = ''
1505  write(filename,"('dbg_cluster_',I3.3,'.txt')")lc1
1506  open(convert='big_endian',unit=201, file=filename, status='replace')
1507  write(201,"(3x,'Time:',F10.6)") time
1508 
1509  cthis => clusters(lc1)
1510 
1511  write(201,"(3x,'Cluster ',I6,' reports ',I6,&
1512  &' particles.')") lc1, cthis%size
1513  write(201,"(3x,' Particles in this cluster include:')")
1514 
1515  nullify(pthis)
1516  if(associated(cthis%particle)) pthis => cthis%particle
1517  do while(associated(pthis))
1518  write(201,"(3x,I8)") pthis%id
1519  if(associated(pthis%next)) then
1520  pthis => pthis%next
1521  else
1522  nullify(pthis)
1523  endif
1524  enddo
1525  close(201)
1526  nullify(cthis)
1527  enddo
1528  endif
1529 
1530 
1531 !``````````````````````````````````````````````````````````````````````!
1532 ! Root Process Only - !
1533 ! !
1534 ! Purpose:: Default message for invalid message id. !
1535 ! !
1536 !``````````````````````````````````````````````````````````````````````!
1537  CASE DEFAULT; if(mype /= clusterpe) return
1538  WRITE(*,"(3x,'No message exists for msgID: ',I4)")lmsgid
1539  write(*,*)''
1540  END SELECT
1541 
1542  return
1543  END SUBROUTINE dbg_print_clusters
1544 
1545  END SUBROUTINE init_print_clusters
1546 
1547 
1548 !......................................................................!
1549 ! Module name: FINL_PRINT_CLUSTERS !
1550 ! !
1551 ! Purpose: Deallocate storage arrays used for collecting cluster data.!
1552 ! !
1553 ! Author: J.Musser Date: Dec-12 !
1554 !......................................................................!
1555  SUBROUTINE finl_print_clusters(dbg_level)
1557  implicit none
1558 
1559 ! Flags used for debugging.
1560 ! 0: No messages
1561 ! 1: Screen only messages
1562 ! 2: Detailed Files are written by each process
1563  INTEGER, intent(in) :: dbg_level
1564 
1565  integer lc1
1566  type(ctype), pointer :: cThis
1567  type(ptype), pointer :: pThis
1568 
1569  if(dbg_level >= 2) write(202,"(3x,'check B')")
1570  call des_mpi_barrier()
1571 
1572  if(allocated(recv_cnt)) deallocate(recv_cnt)
1573  if(allocated(recv_dsp)) deallocate(recv_dsp)
1574 
1575  if(mype /= clusterpe ) then
1576  if(allocated(clusters)) deallocate(clusters)
1577  else
1578  if(allocated(clusters)) then
1579  do lc1=1,size(clusters)
1580  cthis => clusters(lc1)
1581  do while(associated(cthis%particle))
1582  if(associated(cthis%particle%next)) then
1583  pthis => cthis%particle
1584  cthis%particle => pthis%next
1585  nullify(pthis%next)
1586  deallocate(pthis)
1587  nullify(pthis)
1588  else
1589  deallocate(cthis%particle)
1590  nullify(cthis%particle)
1591  endif
1592  cthis%size = cthis%size - 1
1593  enddo
1594  if(cthis%size /= 0) then
1595  write(*,"(3x,'Error deallocating clusters: ', I6)")&
1596  cthis%size
1597  endif
1598  enddo
1599  deallocate(clusters)
1600  endif
1601  endif
1602 
1603 ! Write debug message.
1604  if(dbg_level >= 2) close(202)
1605  if(mype == clusterpe .and. dbg_level >=1) &
1606  write(*,"(/1x,'End data dump ',52('-'),'<'//)")
1607 
1608 ! Clean up local pointers.
1609  nullify(pthis)
1610  nullify(cthis)
1611  END SUBROUTINE finl_print_clusters
1612 
1613 
1614 !......................................................................!
1615 ! Module name: addParticle !
1616 ! !
1617 ! Purpose: Given a specific cluster (this) a new particle object is !
1618 ! is created and added to the cluster link-list. !
1619 ! !
1620 ! Author: J.Musser Date: Dec-12 !
1621 !......................................................................!
1622  SUBROUTINE addparticle(this, lMap, lID)
1624 ! Cluster object getting a new partilced added.
1625  Type(ctype), pointer, intent(inout) :: this
1626 
1627 ! The particle map is used for locating a particle in send/recv data.
1628  integer, intent(in) :: lMap
1629 ! The global ID of the particle. Used mainly for debugging.
1630  integer, intent(in) :: lID
1631 
1632 ! The new particle being added to the cluster.
1633  Type(ptype), pointer :: new
1634 
1635 ! New particle constructor: Allocate the memory and set its entries.
1636  allocate(new)
1637  nullify(new%next)
1638  new%map = lmap
1639  new%id = lid
1640 
1641 ! Update the cluster size (the number of particles in the cluster)
1642  this%size = this%size + 1
1643 
1644 ! Add the new particle to the cluster.
1645  if(this%size == 1) then
1646 ! If this is the first particle, then the cluster should have a null
1647 ! entry for the particle link-list. (Sanity check)
1648  if(associated(this%particle)) then
1649  write(*,"(3x,'Fatal Error (000) adding particle.')")
1650  return
1651  endif
1652  else
1653 ! If this isn't the first particle, then the cluster should have a
1654 ! valid particle in the link list.
1655  if(.not.associated(this%particle)) then
1656  write(*,"(3x,'Fatal Error (001) adding particle.')")
1657  return
1658  endif
1659  new%next => this%particle
1660  endif
1661 
1662  this%particle => new
1663  nullify(new)
1664 
1665  return
1666  END SUBROUTINE addparticle
1667 
1668 
1669 !......................................................................!
1670 ! Module name: getClusterParticleData_1i !
1671 ! !
1672 ! Purpose: Collect data from local processes and send to clusterPE. !
1673 ! The data from cluster-bound particles is placed in a temporary !
1674 ! array for send/recv. !
1675 ! !
1676 ! Incoming data is a 1D Array of Integers !
1677 ! !
1678 ! Author: J.Musser Date: Dec-12 !
1679 !......................................................................!
1680  SUBROUTINE getclusterparticledata_1i(lData, lrbuff, lOut)
1682  implicit none
1683 
1684 ! Data on local process being sent to clusterPE.
1685  integer, intent(in) :: lData(:)
1686 ! Data from local processes received by clusterPE.
1687  integer, allocatable, intent(inout) :: lrbuff(:)
1688 ! Data on local process in cluster-array format.
1689  integer, allocatable, intent(inout), optional :: lOut(:)
1690 
1691 ! Temporary storage array for local data. This data is in array format.
1692  integer, allocatable :: lsbuff(:)
1693 ! Clusters detected by local search
1694  type(cluster_type), pointer :: cluster
1695 ! Particles classified as being in a cluster on the local process.
1696  type(particle_type), pointer :: particle
1697 
1698 ! Generic loop counters
1699  integer lc1, lc2, lc3
1700 ! Error flag.
1701  integer ierr
1702 
1703 ! The receive buffer should be unallocated. Deallocate it otherwise.
1704 ! This array is only important on clusterPE.
1705  if(allocated(lrbuff)) then
1706  if(mype == clusterpe) write(*,"(3x,&
1707  &'Error in getClusterParticleData_1i: ',&
1708  &'Deallocating receive buffer.')")
1709  deallocate(lrbuff)
1710  endif
1711 
1712 ! Allocate the receive buffer (and returned data set)
1713  allocate(lrbuff(recv_sum))
1714 ! Allocate the temporary send buffer.
1715  allocate(lsbuff(send_cnt))
1716 ! Allocate the local return data set
1717  if(present(lout)) allocate(lout(send_cnt))
1718 
1719 ! Populate the send buffer. The send buffer only contains data about
1720 ! particles that belong to clusters.
1721  if(send_cnt > 0) then
1722  NULLIFY(cluster)
1723  lc3 = 0
1724  do lc2 = 1, clustercount
1725  CALL getnextcluster(cluster)
1726  NULLIFY(particle)
1727  do lc1 = 1, cluster%ParticleCount
1728  lc3 = lc3 + 1
1729  CALL getnextparticle(cluster, particle)
1730  lsbuff(lc3) = ldata(particle%ID)
1731  enddo
1732  enddo
1733  endif
1734 
1735 ! Invoke MPI routines.
1736  call des_mpi_gatherv(lsbuff, send_cnt, &
1737  lrbuff, recv_cnt, recv_dsp, &
1738  clusterpe, ierr)
1739 
1740 ! Store the local return data set.
1741  if(present(lout)) lout = lsbuff
1742 
1743 ! Clean up.
1744  deallocate(lsbuff)
1745  nullify(cluster)
1746  nullify(particle)
1747 
1748  return
1749  END SUBROUTINE getclusterparticledata_1i
1750 
1751 
1752 !......................................................................!
1753 ! Module name: getClusterParticleData_2i !
1754 ! !
1755 ! Purpose: Collect data from local processes and send to clusterPE. !
1756 ! The data from cluster-bound particles is placed in a temporary !
1757 ! array for send/recv. !
1758 ! !
1759 ! Incoming data is a 2D Array of Integers !
1760 ! !
1761 ! Author: J.Musser Date: Dec-12 !
1762 !......................................................................!
1763  SUBROUTINE getclusterparticledata_2i(lData, lrbuff, lOut)
1765  implicit none
1766 
1767 ! Data on local process being sent to clusterPE.
1768  integer, intent(in) :: lData(:,:)
1769 ! Data from local processes received by clusterPE.
1770  integer, allocatable, intent(inout) :: lrbuff(:,:)
1771 ! Data on local process in cluster-array format.
1772  integer, allocatable, intent(inout), optional :: lOut(:,:)
1773 ! Temporary storage array for local data. This data is in array format.
1774  integer, allocatable :: lsbuff(:)
1775 
1776 ! Clusters detected by local search
1777  type(cluster_type), pointer :: cluster
1778 ! Particles classified as being in a cluster on the local process.
1779  type(particle_type), pointer :: particle
1780 
1781 ! Generic loop counters
1782  integer lc1, lc2, lc3, lc4
1783 ! Upper/Lower array bounds of lData position 2
1784  integer lbnd, ubnd
1785 ! Error flag.
1786  integer ierr
1787 
1788 ! Get the upper and lower array bounds of the incoming data.
1789  lbnd = lbound(ldata,1)
1790  ubnd = ubound(ldata,1)
1791 
1792 ! The receive buffer should be unallocated. Deallocate it otherwise.
1793 ! This array is only important on clusterPE.
1794  if(allocated(lrbuff)) then
1795  if(mype == 0) write(*,"(3x,&
1796  &'Error in getClusterParticleData_2i: ', &
1797  &'Deallocating receive buffer.')")
1798  deallocate(lrbuff)
1799  endif
1800 
1801 ! Allocate the receive buffer (and returned data set)
1802  allocate(lrbuff(lbnd:ubnd,recv_sum))
1803 ! Allocate the temporary send buffer.
1804  allocate(lsbuff(send_cnt))
1805 ! Allocate the local return data set
1806  if(present(lout)) allocate(lout(lbnd:ubnd,send_cnt))
1807 
1808 ! Populate the send buffer. The send buffer only contains data about
1809 ! particles that belong to clusters.
1810  do lc4=lbnd,ubnd
1811  if(send_cnt > 0) then
1812  lsbuff = -987654321
1813  NULLIFY(cluster)
1814  lc3 = 0
1815  do lc2 = 1, clustercount
1816  CALL getnextcluster(cluster)
1817  NULLIFY(particle)
1818  do lc1 = 1, cluster%ParticleCount
1819  lc3 = lc3 + 1
1820  CALL getnextparticle(cluster, particle)
1821  lsbuff(lc3) = ldata(lc4,particle%ID)
1822  enddo
1823  enddo
1824  endif
1825 
1826 ! Invoke MPI routines.
1827  call des_mpi_gatherv(lsbuff, send_cnt, &
1828  lrbuff(lc4, :), recv_cnt, recv_dsp, &
1829  clusterpe, ierr)
1830 ! Store the local return data set.
1831  if(present(lout)) lout(lc4,:) = lsbuff
1832 
1833  enddo
1834 
1835 ! Clean up.
1836  deallocate(lsbuff)
1837  nullify(cluster)
1838  nullify(particle)
1839 
1840  return
1841  END SUBROUTINE getclusterparticledata_2i
1842 
1843 
1844 !......................................................................!
1845 ! Module name: getClusterParticleData_1d !
1846 ! !
1847 ! Purpose: Collect data from local processes and send to clusterPE. !
1848 ! The data from cluster-bound particles is placed in a temporary !
1849 ! array for send/recv. !
1850 ! !
1851 ! Incoming data is a 1D Array of double precision values. !
1852 ! !
1853 ! Author: J.Musser Date: Dec-12 !
1854 !......................................................................!
1855  SUBROUTINE getclusterparticledata_1d(lData, lrbuff, lOut)
1857  implicit none
1858 
1859 ! Data on local process being sent to clusterPE.
1860  double precision, intent(in) :: lData(:)
1861 ! Data from local processes received by clusterPE.
1862  double precision, allocatable, intent(inout) :: lrbuff(:)
1863 ! Data on local process in cluster-array format.
1864  double precision, allocatable, intent(inout), optional :: lOut(:)
1865 
1866 ! Temporary storage array for local data. This data is in array format.
1867  double precision, allocatable :: lsbuff(:)
1868 
1869 ! Clusters detected by local search
1870  type(cluster_type), pointer :: cluster
1871 ! Particles classified as being in a cluster on the local process.
1872  type(particle_type), pointer :: particle
1873 
1874 ! Generic loop counters
1875  INTEGER lc1, lc2, lc3
1876 ! Error flag.
1877  integer ierr
1878 
1879 ! The receive buffer should be unallocated. Deallocate it otherwise.
1880 ! This array is only important on clusterPE.
1881  if(allocated(lrbuff)) then
1882  if(mype == 0) write(*,"(3x,&
1883  &'Error in getClusterParticleData_1d: ', &
1884  &'Deallocating receive buffer.')")
1885  deallocate(lrbuff)
1886  endif
1887 
1888 ! Allocate the receive buffer (and returned data set)
1889  allocate(lrbuff(recv_sum))
1890 ! Allocate the temporary send buffer.
1891  allocate(lsbuff(send_cnt))
1892 ! Allocate the local return data set
1893  if(present(lout)) allocate(lout(send_cnt))
1894 
1895 ! Populate the send buffer. The send buffer only contains data about
1896 ! particles that belong to clusters.
1897  if(send_cnt > 0) then
1898  NULLIFY(cluster)
1899  lc3 = 0
1900  do lc2 = 1, clustercount
1901  CALL getnextcluster(cluster)
1902  NULLIFY(particle)
1903  do lc1 = 1, cluster%ParticleCount
1904  lc3 = lc3 + 1
1905  CALL getnextparticle(cluster, particle)
1906  lsbuff(lc3) = ldata(particle%ID)
1907  enddo
1908  enddo
1909  endif
1910 
1911 ! Invoke MPI routines.
1912  call des_mpi_gatherv(lsbuff, send_cnt, &
1913  lrbuff, recv_cnt, recv_dsp, &
1914  clusterpe, ierr)
1915 
1916 ! Store the local return data set.
1917  if(present(lout)) lout = lsbuff
1918 
1919 ! Clean up.
1920  deallocate(lsbuff)
1921  nullify(cluster)
1922  nullify(particle)
1923 
1924  return
1925  END SUBROUTINE getclusterparticledata_1d
1926 
1927 
1928 !......................................................................!
1929 ! Module name: getClusterParticleData_2d !
1930 ! !
1931 ! Purpose: Collect data from local processes and send to clusterPE. !
1932 ! The data from cluster-bound particles is placed in a temporary !
1933 ! array for send/recv. !
1934 ! !
1935 ! Incoming data is a 2D Array of double precision values. !
1936 ! !
1937 ! Author: J.Musser Date: Dec-12 !
1938 !......................................................................!
1939  SUBROUTINE getclusterparticledata_2d(lData, lrbuff, lOut)
1941  implicit none
1942 
1943 ! Data on local process being sent to clusterPE.
1944  double precision, intent(in) :: lData(:,:)
1945 ! Data from local processes received by clusterPE.
1946  double precision, allocatable, intent(inout) :: lrbuff(:,:)
1947 ! Data on local process in cluster-array format.
1948  double precision, allocatable, intent(inout), optional :: lOut(:,:)
1949 
1950 ! Temporary storage array for local data. This data is in array format.
1951  double precision, allocatable :: lsbuff(:) ! send buffer
1952 
1953 ! Clusters detected by local search
1954  type(cluster_type), pointer :: cluster
1955 ! Particles classified as being in a cluster on the local process.
1956  type(particle_type), pointer :: particle
1957 
1958 ! Generic loop counters
1959  integer lc1, lc2, lc3, lc4
1960 ! Upper/Lower array bounds of lData position 2
1961  integer lbnd, ubnd
1962 ! Error flag.
1963  integer ierr
1964 
1965 ! Get the upper and lower array bounds of the incoming data.
1966  lbnd = lbound(ldata,1)
1967  ubnd = ubound(ldata,1)
1968 
1969 ! The receive buffer should be unallocated. Deallocate it otherwise.
1970 ! This array is only important on clusterPE.
1971  if(allocated(lrbuff)) then
1972  if(mype == 0) write(*,"(3x,&
1973  &'Error in getClusterParticleData_2d: ', &
1974  &'Deallocating receive buffer.')")
1975  deallocate(lrbuff)
1976  endif
1977 
1978 ! Allocate the receive buffer (and returned data set)
1979  allocate(lrbuff(lbnd:ubnd,recv_sum))
1980 ! Allocate the temporary send buffer.
1981  allocate(lsbuff(send_cnt))
1982 ! Allocate the local return data set
1983  if(present(lout)) allocate(lout(lbnd:ubnd,send_cnt))
1984 
1985 ! Populate the send buffer. The send buffer only contains data about
1986 ! particles that belong to clusters.
1987  do lc4=lbnd,ubnd
1988  if(send_cnt > 0) then
1989  lsbuff = -9.87654321
1990  NULLIFY(cluster)
1991  lc3 = 0
1992  do lc2 = 1, clustercount
1993  CALL getnextcluster(cluster)
1994  NULLIFY(particle)
1995  do lc1 = 1, cluster%ParticleCount
1996  lc3 = lc3 + 1
1997  CALL getnextparticle(cluster, particle)
1998  lsbuff(lc3) = ldata(lc4,particle%ID)
1999  enddo
2000  enddo
2001  endif
2002 
2003 ! Invoke MPI routines.
2004  call des_mpi_gatherv(lsbuff, send_cnt, &
2005  lrbuff(lc4,:), recv_cnt, recv_dsp, &
2006  clusterpe, ierr)
2007 
2008 ! Store the local return data set.
2009  if(present(lout)) lout(lc4,:) = lsbuff
2010 
2011  enddo
2012 
2013 ! Clean up.
2014  deallocate(lsbuff)
2015  nullify(cluster)
2016  nullify(particle)
2017 
2018  return
2019  END SUBROUTINE getclusterparticledata_2d
2020 
2021 
2022 !......................................................................!
2023 ! Module name: getClusterParticleData_1l !
2024 ! !
2025 ! Purpose: Collect data from local processes and send to clusterPE. !
2026 ! The data from cluster-bound particles is placed in a temporary !
2027 ! array for send/recv. !
2028 ! !
2029 ! Incoming data is a 1D Array of logicals. !
2030 ! !
2031 ! Note: Logicals are converted to integers for send/recv, then !
2032 ! converted back to logical values. !
2033 ! !
2034 ! Author: J.Musser Date: Dec-12 !
2035 !......................................................................!
2036  SUBROUTINE getclusterghostdata(lrbuff, lOut)
2038  implicit none
2039 
2040 ! Data from local processes received by clusterPE.
2041  logical, allocatable, intent(inout) :: lrbuff(:)
2042 ! Data on local process in cluster-array format.
2043  logical, allocatable, intent(inout), optional :: lOut(:)
2044 
2045 ! Data on local process in cluster-array format (converted to integer)
2046  integer, allocatable :: lsbuff_i(:)
2047 ! Data from local processes received by clusterPE (converted to integer)
2048  integer, allocatable :: lrbuff_i(:)
2049 
2050 ! Clusters detected by local search
2051  type(cluster_type), pointer :: cluster
2052 ! Particles classified as being in a cluster on the local process.
2053  type(particle_type), pointer :: particle
2054 
2055 ! Generic loop counters
2056  INTEGER lc1, lc2, lc3
2057 ! Error flag.
2058  integer ierr
2059 
2060 ! The receive buffer should be unallocated. Deallocate it otherwise.
2061 ! This array is only important on clusterPE.
2062  if(allocated(lrbuff)) then
2063  if(mype == 0) write(*,"(3x,&
2064  &'Error in getClusterParticleData_1l: ',&
2065  &'Deallocating receive buffer.')")
2066  deallocate(lrbuff)
2067  endif
2068 
2069 ! Allocate the receive buffer (and returned data set)
2070  allocate(lrbuff(recv_sum)); lrbuff = .false.
2071 ! Allocate the local return data set.
2072  if(present(lout)) allocate(lout(send_cnt))
2073 
2074 ! Allocate the temporary receiver buffer.
2075  allocate(lrbuff_i(recv_sum)); lrbuff_i = 0
2076 ! Allocate the temporary send buffer.
2077  allocate(lsbuff_i(send_cnt)); lsbuff_i = 0
2078 
2079 ! Populate the send buffer. The send buffer only contains data about
2080 ! particles that belong to clusters.
2081  if(send_cnt > 0) then
2082  NULLIFY(cluster)
2083  lc3 = 0
2084  do lc2 = 1, clustercount
2085  CALL getnextcluster(cluster)
2086  NULLIFY(particle)
2087  do lc1 = 1, cluster%ParticleCount
2088  lc3 = lc3 + 1
2089  CALL getnextparticle(cluster, particle)
2090 ! Convert logical to integer.
2091  if(is_ghost(particle%ID)) lsbuff_i(lc3) = 1
2092  enddo
2093  enddo
2094  endif
2095 ! Invoke MPI routines.
2096  call des_mpi_gatherv(lsbuff_i, send_cnt, &
2097  lrbuff_i, recv_cnt, recv_dsp, &
2098  clusterpe, ierr)
2099 
2100 ! Convert integer back to logical.
2101  do lc1=1,recv_sum
2102  if(lrbuff_i(lc1) == 1) lrbuff(lc1) = .true.
2103  enddo
2104 
2105 ! Convert and store the local return data set.
2106  if(present(lout)) then
2107  lout = .false.
2108  do lc1 = 1, send_cnt
2109  if(lsbuff_i(lc1) == 1) lout(lc1) = .true.
2110  enddo
2111  endif
2112 
2113 ! Clean up.
2114  deallocate(lrbuff_i)
2115  deallocate(lsbuff_i)
2116  nullify(cluster)
2117  nullify(particle)
2118 
2119  return
2120  END SUBROUTINE getclusterghostdata
2121 
2122 !......................................................................!
2123 ! Module name: getClusterFieldData_1d !
2124 ! !
2125 ! Purpose: Collect field (continuum) data from local processes and !
2126 ! send to clusterPE. The data from the field associated with !
2127 ! cluster-bound particles is accessed by the particke map and not !
2128 ! the global IJK value. !
2129 ! !
2130 ! Incoming data is a 1D Array of double precision values. !
2131 ! !
2132 ! !
2133 ! Author: J.Musser Date: Dec-12 !
2134 !......................................................................!
2135  SUBROUTINE getclusterfielddata_1d(lData, lrbuff, lOut)
2137  implicit none
2138 
2139 ! Field data on local process being sent to clusterPE.
2140  double precision, intent(in) :: lData(:)
2141 ! Field data from local processes received by clusterPE.
2142  double precision, allocatable, intent(inout) :: lrbuff(:)
2143 ! Field ata on local process in cluster-array format.
2144  double precision, allocatable, intent(inout), optional :: lOut(:)
2145 
2146  double precision, allocatable :: lsbuff(:) ! send buffer
2147 
2148 ! Clusters detected by local search
2149  type(cluster_type), pointer :: cluster
2150 ! Particles classified as being in a cluster on the local process.
2151  type(particle_type), pointer :: particle
2152 
2153 ! Generic loop counters
2154  integer lc1, lc2, lc3
2155 ! IJK index of fluid cell containing particle
2156  integer ijk
2157 ! Error flag.
2158  integer ierr
2159 
2160 ! The receive buffer should be unallocated. Deallocate it otherwise.
2161 ! This array is only important on clusterPE.
2162  if(allocated(lrbuff)) then
2163  if(mype == 0) write(*,"(3x,&
2164  &'Error in getClusterFieldData_1d: ', &
2165  &'Deallocating receive buffer.')")
2166  deallocate(lrbuff)
2167  endif
2168 
2169 ! Allocate the receive buffer (and returned data set)
2170  allocate(lrbuff(recv_sum))
2171 ! Allocate the temporary send buffer.
2172  allocate(lsbuff(send_cnt))
2173 ! Allocate the local return data set.
2174  if(present(lout)) allocate(lout(send_cnt))
2175 
2176 ! Populate the send buffer. The send buffer only contains data about
2177 ! particles that belong to clusters.
2178  if(send_cnt > 0) then
2179  NULLIFY(cluster)
2180  lc3 = 0
2181  do lc2 = 1, clustercount
2182  CALL getnextcluster(cluster)
2183  NULLIFY(particle)
2184  do lc1 = 1, cluster%ParticleCount
2185  lc3 = lc3 + 1
2186  CALL getnextparticle(cluster, particle)
2187 ! Use the particke fluid cell IJK to access the field data.
2188  ijk = pijk(particle%ID,4)
2189 ! Ghost particles have an IJK of 0. Since data from ghost particles is
2190 ! not needed, set the value as undefined.
2191  if(ijk == 0) then
2192  lsbuff(lc3) = undefined
2193  else
2194  lsbuff(lc3) = ldata(ijk)
2195  endif
2196  enddo
2197  enddo
2198  endif
2199 
2200 ! Invoke MPI routines.
2201  call des_mpi_gatherv(lsbuff, send_cnt, &
2202  lrbuff, recv_cnt, recv_dsp, &
2203  clusterpe, ierr)
2204 
2205 ! Store the local return data set.
2206  if(present(lout)) lout = lsbuff
2207 
2208 ! Clean up.
2209  deallocate(lsbuff)
2210  nullify(cluster)
2211  nullify(particle)
2212 
2213  return
2214  END SUBROUTINE getclusterfielddata_1d
2215 
2216 
2217 !......................................................................!
2218 ! Module name: getClusterFieldData_3d !
2219 ! !
2220 ! Purpose: Collect field (continuum) data from local processes and !
2221 ! send to clusterPE. The data from the field associated with !
2222 ! cluster-bound particles is placed in a temporary and is no longer !
2223 ! IJK bound. !
2224 ! !
2225 ! Incoming data are three 1D Array of double precision values. !
2226 ! !
2227 ! !
2228 ! Author: J.Musser Date: Dec-12 !
2229 !......................................................................!
2230  SUBROUTINE getclusterfielddata_3d(lData_1, lData_2, lData_3, &
2231  lrbuff, lout)
2233  implicit none
2234 
2235 ! Data on local process being sent to clusterPE.
2236  double precision, intent(in) :: lData_1(:) ! x-axis
2237  double precision, intent(in) :: lData_2(:) ! y-axis
2238  double precision, intent(in) :: lData_3(:) ! z-axis
2239 
2240 ! Data from local processes received by clusterPE.
2241  double precision, allocatable, intent(inout) :: lrbuff(:,:)
2242 ! Data on local process in cluster-array format.
2243  double precision, allocatable, intent(inout), optional :: lOut(:,:)
2244 ! Temporary storage array for local data. This data is in array format.
2245  double precision, allocatable :: lsbuff(:) ! send buffer
2246 
2247 ! Clusters detected by local search
2248  type(cluster_type), pointer :: cluster
2249 ! Particles classified as being in a cluster on the local process.
2250  type(particle_type), pointer :: particle
2251 
2252 ! Generic loop counters
2253  integer lc1, lc2, lc3
2254 ! IJK index of fluid cell containing particle
2255  integer ijk
2256 ! Error flag.
2257  integer ierr
2258 
2259 ! The receive buffer should be unallocated. Deallocate it otherwise.
2260 ! This array is only important on clusterPE.
2261  if(allocated(lrbuff)) then
2262  if(mype == 0) write(*,"(3x,&
2263  &'Error in getClusterFieldData_3d: ', &
2264  &'Deallocating receive buffer.')")
2265  deallocate(lrbuff)
2266  endif
2267 
2268 ! Allocate the receive buffer (and returned data set)
2269  allocate(lrbuff(recv_sum,1:3))
2270 ! Allocate the temporary send buffer.
2271  allocate(lsbuff(send_cnt))
2272 ! Allocate the local return data set
2273  if(present(lout)) allocate(lout(send_cnt,1:3))
2274 
2275 ! Populate the send buffer. The send buffer only contains data about
2276 ! particles that belong to clusters.
2277  if(send_cnt > 0) then
2278  lsbuff = -9.87654321
2279  NULLIFY(cluster)
2280  lc3 = 0
2281  do lc2 = 1, clustercount
2282  CALL getnextcluster(cluster)
2283  NULLIFY(particle)
2284  do lc1 = 1, cluster%ParticleCount
2285  lc3 = lc3 + 1
2286  CALL getnextparticle(cluster, particle)
2287 ! Use the particke fluid cell IJK to access the field data.
2288  ijk = pijk(particle%ID,4)
2289 ! Ghost particles have an IJK of 0. Since data from ghost particles is
2290 ! not needed, set the value as undefined.
2291  if(ijk == 0) then
2292  lsbuff(lc3) = undefined
2293  else
2294  lsbuff(lc3) = ldata_1(ijk)
2295  endif
2296  enddo
2297  enddo
2298  endif
2299 ! Invoke MPI routines.
2300  call des_mpi_gatherv(lsbuff, send_cnt, &
2301  lrbuff(:,1), recv_cnt, recv_dsp, &
2302  clusterpe, ierr)
2303 ! Store the local return data set.
2304  if(present(lout)) lout(:,1) = lsbuff
2305 
2306  if(send_cnt > 0) then
2307  lsbuff = -9.87654321
2308  NULLIFY(cluster)
2309  lc3 = 0
2310  do lc2 = 1, clustercount
2311  CALL getnextcluster(cluster)
2312  NULLIFY(particle)
2313  do lc1 = 1, cluster%ParticleCount
2314  lc3 = lc3 + 1
2315  CALL getnextparticle(cluster, particle)
2316 ! Use the particke fluid cell IJK to access the field data.
2317  ijk = pijk(particle%ID,4)
2318 ! Ghost particles have an IJK of 0. Since data from ghost particles is
2319 ! not needed, set the value as undefined.
2320  if(ijk == 0) then
2321  lsbuff(lc3) = undefined
2322  else
2323  lsbuff(lc3) = ldata_2(ijk)
2324  endif
2325  enddo
2326  enddo
2327  endif
2328 ! Invoke MPI routines.
2329  call des_mpi_gatherv(lsbuff, send_cnt, &
2330  lrbuff(:,2), recv_cnt, recv_dsp, &
2331  clusterpe, ierr)
2332 ! Store the local return data set.
2333  if(present(lout)) lout(:,2) = lsbuff
2334 
2335  if(do_k) then
2336  if(send_cnt > 0) then
2337  lsbuff = -9.87654321
2338  NULLIFY(cluster)
2339  lc3 = 0
2340  do lc2 = 1, clustercount
2341  CALL getnextcluster(cluster)
2342  NULLIFY(particle)
2343  do lc1 = 1, cluster%ParticleCount
2344  lc3 = lc3 + 1
2345  CALL getnextparticle(cluster, particle)
2346 ! Use the particke fluid cell IJK to access the field data.
2347  ijk = pijk(particle%ID,4)
2348 ! Ghost particles have an IJK of 0. Since data from ghost particles is
2349 ! not needed, set the value as undefined.
2350  if(ijk == 0) then
2351  lsbuff(lc3) = undefined
2352  else
2353  lsbuff(lc3) = ldata_3(ijk)
2354  endif
2355  enddo
2356  enddo
2357  endif
2358 ! Invoke MPI routines.
2359  call des_mpi_gatherv(lsbuff, send_cnt, &
2360  lrbuff(:,3), recv_cnt, recv_dsp, &
2361  clusterpe, ierr)
2362 ! Store the local return data set.
2363  if(present(lout)) lout(:,3) = lsbuff
2364 
2365  endif
2366 
2367 ! Clean up.
2368  deallocate(lsbuff)
2369  nullify(cluster)
2370  nullify(particle)
2371 
2372  return
2373  END SUBROUTINE getclusterfielddata_3d
2374 
2375 
2376 !......................................................................!
2377 ! Module name: sendClusterData_1d !
2378 ! !
2379 ! Purpose: Take cluster data from clusterPE and send it to each !
2380 ! process. (Storage of output data for visualization) !
2381 ! !
2382 ! Note: The local storage array is initialized to zero by default. !
2383 ! A different value may be used by specifying initValue. !
2384 ! !
2385 ! !
2386 ! Author: J.Musser Date: Dec-12 !
2387 !......................................................................!
2388  SUBROUTINE sendclusterdata_1d(lsbuff, lData)
2390  implicit none
2391 
2392 ! Data on clusterPE being distributed to the other processes.
2393  double precision, intent(in) :: lsbuff(:)
2394 ! Storage array on local process.
2395  double precision, intent(inout) :: lData(:)
2396 
2397 ! Data from clusterPE received by local process.
2398  double precision, allocatable :: lrbuff(:)
2399 
2400 ! Clusters detected by local search
2401  type(cluster_type), pointer :: cluster
2402 ! Particles classified as being in a cluster on the local process.
2403  type(particle_type), pointer :: particle
2404 
2405 ! Generic loop counters
2406  integer lc1, lc2, lc3
2407 ! Error flag.
2408  integer ierr
2409 
2410 ! Allocate the temporary receive buffer on local process.
2411  allocate(lrbuff(send_cnt))
2412 
2413 ! Invoke MPI routines.
2414  call des_mpi_scatterv(lsbuff, recv_cnt, recv_dsp, lrbuff, &
2415  send_cnt, clusterpe, ierr)
2416 
2417 ! Map the received data back to individual particles using the local
2418 ! cluster data.
2419  if(send_cnt > 0) then
2420  NULLIFY(cluster)
2421  lc3 = 0
2422  do lc2 = 1, clustercount
2423  CALL getnextcluster(cluster)
2424  NULLIFY(particle)
2425  do lc1 = 1, cluster%ParticleCount
2426  lc3 = lc3 + 1
2427  CALL getnextparticle(cluster, particle)
2428  ldata(particle%ID) = lrbuff(lc3)
2429  enddo
2430  enddo
2431  endif
2432 
2433 ! Clean up.
2434  deallocate(lrbuff)
2435  nullify(cluster)
2436  nullify(particle)
2437 
2438  return
2439  END SUBROUTINE sendclusterdata_1d
2440 
2441 
2442 
2443  END MODULE des_cluster
subroutine getclusterfielddata_1d(lData, lrbuff, lOut)
integer send_cnt
subroutine getclusterghostdata(lrbuff, lOut)
double precision, dimension(:), allocatable ep_g
Definition: fldvar_mod.f:15
subroutine gettopcluster(cluster)
Definition: dbg_mod.f:18
integer clustercount
subroutine delete_particles_in_cluster(cluster)
subroutine getclusterparticledata_2d(lData, lrbuff, lOut)
double precision, parameter undefined
Definition: param1_mod.f:18
subroutine addparticle(this, lMap, lID)
subroutine des_mpi_barrier
integer recv_sum
subroutine deletetopparticle_in_psearchhistory()
subroutine gettopparticle_in_psearchhistory(particle)
integer numpes
Definition: compar_mod.f:24
subroutine create_cluster(cluster)
subroutine add_particle_to_cluster(cluster, pID)
integer, parameter clusterpe
subroutine add_particle_to_psearchhistory(particle, pID)
type(particle_type), pointer psearch_history_ll
double precision, dimension(:), allocatable v_g
Definition: fldvar_mod.f:99
double precision, dimension(:), allocatable w_g
Definition: fldvar_mod.f:111
Definition: run_mod.f:13
double precision, parameter large_number
Definition: param1_mod.f:23
Definition: param_mod.f:2
subroutine dbg_print_clusters(lmsgID, lmsg, dbg)
integer mype
Definition: compar_mod.f:24
subroutine getclusterparticledata_1d(lData, lrbuff, lOut)
double precision, dimension(:), allocatable mu_g
Definition: physprop_mod.f:68
subroutine getnextcluster(cluster)
subroutine getclusterparticledata_2i(lData, lrbuff, lOut)
integer psearchhistorycount
double precision, dimension(:), allocatable u_g
Definition: fldvar_mod.f:87
type(cluster_type), pointer cluster_ll
<<----------------— DMP Related Variables -----------------—>>>!
integer, dimension(:), allocatable recv_cnt
subroutine getclusterparticledata_1i(lData, lrbuff, lOut)
subroutine getclusterfielddata_3d(lData_1, lData_2, lData_3, lrbuff, lOut)
subroutine delete_clusters()
subroutine getnextparticle(cluster, particle)
subroutine sendclusterdata_1d(lsbuff, lData)
double precision time
Definition: run_mod.f:45
subroutine finl_print_clusters(dbg_level)
subroutine print_clusters
subroutine delete_psearchhistory()
integer, dimension(:), allocatable recv_dsp
subroutine init_print_clusters(dbg_level)
double precision, dimension(:), allocatable ro_g
Definition: fldvar_mod.f:32
type(ctype), dimension(:), allocatable, target clusters
subroutine deletetopcluster(cluster)
double precision, parameter zero
Definition: param1_mod.f:27
integer clustercount_all