MFIX  2016-1
calc_collision_wall_mod.f
Go to the documentation of this file.
1 !vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvC
2 ! C
3 ! Module name: CALC_COLLISION_WALL C
4 ! Author: Rahul Garg Date: 1-Dec-2013 C
5 ! C
6 ! Purpose: subroutines for particle-wall collisions when cutcell is C
7 ! used. Also contains rehack of routines for cfslide and C
8 ! cffctow which might be different from the stand alone C
9 ! routines. Eventually all the DEM routines will be C
10 ! consolidated. C
11 ! C
12 !^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^C
14 
15  PRIVATE
18 
19  CONTAINS
20 
21 !VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV!
22 ! !
23 ! !
24 ! !
25 ! !
26 ! !
27 ! !
28 !^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!
30 
31  USE run
32  USE param1
33  USE desgrid
34  USE discretelement
35  USE geometry
36  USE compar
37  USE constant
38  USE indices
39  USE stl
41  USE functions
42  Implicit none
43 
44  INTEGER :: LL
45  INTEGER :: IJK, NF
46  DOUBLE PRECISION ::OVERLAP_N, SQRT_OVERLAP
47 
48  DOUBLE PRECISION :: V_REL_TRANS_NORM, DISTSQ, RADSQ, CLOSEST_PT(dimn)
49 ! local normal and tangential forces
50  DOUBLE PRECISION :: NORMAL(dimn), VREL_T(dimn), DIST(dimn), DISTMOD
51  DOUBLE PRECISION, DIMENSION(DIMN) :: FTAN, FNORM, OVERLAP_T
52 
53  LOGICAL :: DES_LOC_DEBUG
54  INTEGER :: CELL_ID, cell_count
55  INTEGER :: PHASELL
56 
57  DOUBLE PRECISION :: TANGENT(dimn)
58  DOUBLE PRECISION :: FTMD, FNMD
59 ! local values used spring constants and damping coefficients
60  DOUBLE PRECISION ETAN_DES_W, ETAT_DES_W, KN_DES_W, KT_DES_W
61 
62  double precision :: MAG_OVERLAP_T
63 
64  double precision :: line_t
65 ! flag to tell if the orthogonal projection of sphere center to
66 ! extended plane detects an overlap
67 
68  DOUBLE PRECISION :: MAX_DISTSQ, DISTAPART, FORCE_COH, R_LM
69  INTEGER :: MAX_NF, axis
70  DOUBLE PRECISION, DIMENSION(3) :: PARTICLE_MIN, PARTICLE_MAX, POS_TMP
71 
72  des_loc_debug = .false. ; debug_des = .false.
73  focus_particle = -1
74 
75 !$omp parallel default(none) private(LL,ijk,MAG_OVERLAP_T, &
76 !$omp cell_id,radsq,particle_max,particle_min,tangent, &
77 !$omp axis,nf,closest_pt,dist,r_lm,distapart,force_coh,distsq, &
78 !$omp line_t,max_distsq,max_nf,normal,distmod,overlap_n,VREL_T, &
79 !$omp v_rel_trans_norm,phaseLL,sqrt_overlap,kn_des_w,kt_des_w, &
80 !$omp etan_des_w,etat_des_w,fnorm,overlap_t,ftan,ftmd,fnmd,pos_tmp) &
81 !$omp shared(max_pip,focus_particle,debug_des, &
82 !$omp pijk,dg_pijk,i_of,j_of,k_of,des_pos_new, &
83 !$omp des_radius,facets_at_dg,vertex, &
84 !$omp hert_kwn,hert_kwt,kn_w,kt_w,des_coll_model_enum,mew_w,tow, &
85 !$omp des_etan_wall,des_etat_wall,dtsolid,fc,norm_face, &
86 !$omp wall_collision_facet_id,wall_collision_PFT,use_cohesion, &
87 !$omp van_der_waals,wall_hamaker_constant,wall_vdw_outer_cutoff, &
88 !$omp wall_vdw_inner_cutoff,asperities,surface_energy)
89 !$omp do
90  DO ll = 1, max_pip
91 
92  IF(ll.EQ.focus_particle) debug_des = .true.
93 
94 ! skipping non-existent particles or ghost particles
95 ! make sure the particle is not classified as a new 'entering' particle
96 ! or is already marked as a potential exiting particle
97  IF(.NOT.is_normal(ll)) cycle
98 
99  cell_id = dg_pijk(ll)
100 
101 ! If no neighboring facet in the surrounding 27 cells, then exit
102  IF(facets_at_dg(cell_id)%COUNT < 1) THEN
103  wall_collision_facet_id(:,ll) = -1
104  wall_collision_pft(:,:,ll) = 0.0d0
105  cycle
106  ENDIF
107 
108 ! Check particle LL for wall contacts
109  radsq = des_radius(ll)*des_radius(ll)
110 
111  particle_max(:) = des_pos_new( ll,:) + des_radius(ll)
112  particle_min(:) = des_pos_new( ll,:) - des_radius(ll)
113 
114  DO cell_count = 1, facets_at_dg(cell_id)%count
115 
116  axis = facets_at_dg(cell_id)%dir(cell_count)
117 
118  nf = facets_at_dg(cell_id)%id(cell_count)
119 
120 ! Compute particle-particle VDW cohesive short-range forces
121  IF(use_cohesion .AND. van_der_waals) THEN
122 
123  CALL closestptpointtriangle(des_pos_new(ll,:), &
124  vertex(:,:,nf), closest_pt(:))
125 
126  dist(:) = closest_pt(:) - des_pos_new(ll,:)
127  distsq = dot_product(dist, dist)
128  r_lm = 2*des_radius(ll)
129 
130  IF(distsq < (r_lm+wall_vdw_outer_cutoff)**2) THEN
131  IF(distsq > (wall_vdw_inner_cutoff+r_lm)**2) THEN
132  distapart = (sqrt(distsq)-r_lm)
133  force_coh = wall_hamaker_constant*des_radius(ll) /&
134  (12d0*distapart**2)*(asperities/(asperities + &
135  des_radius(ll)) + one/(one+asperities/ &
136  distapart)**2)
137  ELSE
138  force_coh = 2d0*pi*surface_energy*des_radius(ll)* &
139  (asperities/(asperities+des_radius(ll)) + one/ &
140  (one+asperities/wall_vdw_inner_cutoff)**2 )
141  ENDIF
142  fc(ll,:) = fc(ll,:) + dist(:)*force_coh/sqrt(distsq)
143  ENDIF
144  ENDIF
145 
146  if (facets_at_dg(cell_id)%min(cell_count) > &
147  particle_max(axis)) then
148  call remove_collision(ll, nf, wall_collision_facet_id)
149  cycle
150  endif
151 
152  if (facets_at_dg(cell_id)%max(cell_count) < &
153  particle_min(axis)) then
154  call remove_collision(ll, nf, wall_collision_facet_id)
155  cycle
156  endif
157 
158 ! Checking all the facets is time consuming due to the expensive
159 ! separating axis test. Remove this facet from contention based on
160 ! a simple orthogonal projection test.
161 
162 ! Parametrize a line as p = p_0 + t normal and intersect with the
163 ! triangular plane. If t>0, then point is on the non-fluid side of
164 ! the plane. If the plane normal is assumed to point toward the fluid.
165 
166 ! -undefined, because non zero values will imply the sphere center
167 ! is on the non-fluid side of the plane. Since the testing
168 ! is with extended plane, this could very well happen even
169 ! when the particle is well inside the domain (assuming the plane
170 ! normal points toward the fluid). See the pic below. So check
171 ! only when line_t is negative
172 
173 ! \ Solid /
174 ! \ Side /
175 ! \ /
176 ! \ /
177 ! Wall 1, fluid side \ / Wall 2, fluid side
178 ! \/
179 ! o particle
180 !
181 ! line_t will be positive for wall 1 (incorrectly indicating center
182 ! is outside the domain) and line_t will be negative for wall 2.
183 !
184 ! Therefore, only stick with this test when line_t is negative and let
185 ! the separating axis test take care of the other cases.
186 
187 ! Since this is for checking static config, line's direction is the
188 ! same as plane's normal. For moving particles, the line's normal will
189 ! be along the point joining new and old positions.
190 
191  line_t = dot_product(vertex(1,:,nf) - des_pos_new(ll,:),&
192  norm_face(:,nf))
193 
194 ! k - rad >= tol_orth, where k = -line_t, then orthogonal
195 ! projection is false. Substituting for k
196 ! => line_t + rad <= -tol_orth
197 ! choosing tol_orth = 0.01% of des_radius = 0.0001*des_radius
198 
199 ! Orthogonal projection will detect false positives even
200 ! when the particle does not overlap the triangle.
201 ! However, if the orthogonal projection shows no overlap, then
202 ! that is a big fat negative and overlaps are not possible.
203  if((line_t.le.-1.0001d0*des_radius(ll))) then ! no overlap
204  call remove_collision(ll,nf,wall_collision_facet_id)
205  cycle
206  ENDIF
207 
208  pos_tmp = des_pos_new(ll,:)
209  CALL closestptpointtriangle(pos_tmp, &
210  vertex(:,:,nf), closest_pt(:))
211 
212  dist(:) = closest_pt(:) - des_pos_new(ll,:)
213  distsq = dot_product(dist, dist)
214 
215  IF(distsq .GE. radsq - small_number) THEN !No overlap exists
216  call remove_collision(ll,nf,wall_collision_facet_id)
217  cycle
218  ENDIF
219 
220  max_distsq = distsq
221  max_nf = nf
222 
223 ! Assign the collision normal based on the facet with the
224 ! largest overlap.
225  normal(:) = dist(:)/sqrt(distsq)
226 
227 ! Facet's normal is correct normal only when the intersection is with
228 ! the face. When the intersection is with edge or vertex, then the
229 ! normal is based on closest pt and sphere center. The definition above
230 ! of the normal is generic enough to account for differences between
231 ! vertex, edge, and facet.
232 
233 ! Calculate the particle/wall overlap.
234  distmod = sqrt(max_distsq)
235  overlap_n = des_radius(ll) - distmod
236 
237 ! Calculate the translational relative velocity
238  CALL cfrelvel_wall(ll, v_rel_trans_norm,vrel_t, &
239  normal, distmod)
240 
241 ! Calculate the spring model parameters.
242  phasell = pijk(ll,5)
243 
244 ! Hertz vs linear spring-dashpot contact model
245  IF (des_coll_model_enum .EQ. hertzian) THEN
246  sqrt_overlap = sqrt(overlap_n)
247  kn_des_w = hert_kwn(phasell)*sqrt_overlap
248  kt_des_w = hert_kwt(phasell)*sqrt_overlap
249  sqrt_overlap = sqrt(sqrt_overlap)
250  etan_des_w = des_etan_wall(phasell)*sqrt_overlap
251  etat_des_w = des_etat_wall(phasell)*sqrt_overlap
252  ELSE
253  kn_des_w = kn_w
254  kt_des_w = kt_w
255  etan_des_w = des_etan_wall(phasell)
256  etat_des_w = des_etat_wall(phasell)
257  ENDIF
258 
259 ! Calculate the normal contact force
260  fnorm(:) = -(kn_des_w * overlap_n * normal(:) + &
261  etan_des_w * v_rel_trans_norm * normal(:))
262 
263 ! Calculate the tangential displacement.
264  overlap_t(:) = dtsolid*vrel_t(:) + get_collision(ll, &
265  nf, wall_collision_facet_id, wall_collision_pft)
266  mag_overlap_t = sqrt(dot_product(overlap_t, overlap_t))
267 
268 ! Check for Coulombs friction law and limit the maximum value of the
269 ! tangential force on a particle in contact with a wall.
270  IF(mag_overlap_t > 0.0) THEN
271 ! Tangential froce from spring.
272  ftmd = kt_des_w*mag_overlap_t
273 ! Max force before the on set of frictional slip.
274  fnmd = mew_w*sqrt(dot_product(fnorm,fnorm))
275 ! Direction of tangential force.
276  tangent = overlap_t/mag_overlap_t
277  IF(ftmd < fnmd) THEN
278  ftan = -ftmd * tangent
279  ELSE
280  ftan = -fnmd * tangent
281  overlap_t = (fnmd/kt_des_w) * tangent
282  ENDIF
283  ELSE
284  ftan = 0.0
285  ENDIF
286 ! Add in the tangential dashpot damping force
287  ftan = ftan - etat_des_w*vrel_t(:)
288 
289 ! Save the tangential displacement.
290  CALL update_collision(overlap_t, ll, nf, &
291  wall_collision_facet_id, wall_collision_pft)
292 
293 ! Add the collision force to the total forces acting on the particle.
294  fc(ll,:) = fc(ll,:) + fnorm(:) + ftan(:)
295 
296 ! Add the torque force to the toal torque acting on the particle.
297  tow(ll,:) = tow(ll,:) + distmod*des_crossprdct(normal,ftan)
298 
299  ENDDO
300 
301  ENDDO
302 !$omp end do
303 !$omp end parallel
304 
305  RETURN
306 
307  contains
308 
309 !......................................................................!
310 ! Function: GET_COLLISION !
311 ! !
312 ! Purpose: Return the integrated (t0->t) tangential displacement. !
313 !......................................................................!
314  FUNCTION get_collision(LLL,FACET_ID,WALL_COLLISION_FACET_ID, &
315  wall_collision_pft)
317  use stl_dbg_des, only: write_this_stl
319 
320  use error_manager
321 
322  IMPLICIT NONE
323 
324  DOUBLE PRECISION :: GET_COLLISION(dimn)
325  INTEGER, INTENT(IN) :: LLL,FACET_ID
326  INTEGER, INTENT(INOUT) :: WALL_COLLISION_FACET_ID(:,:)
327  DOUBLE PRECISION, INTENT(INOUT) :: WALL_COLLISION_PFT(:,:,:)
328  INTEGER :: CC, FREE_INDEX, LC, dgIJK
329 
330  INTEGER :: lSIZE1, lSIZE2, lSIZE3
331  INTEGER, ALLOCATABLE :: tmpI2(:,:)
332  DOUBLE PRECISION, ALLOCATABLE :: tmpR3(:,:,:)
333 
334  free_index = -1
335 
336  do cc = 1, collision_array_max
337  if (facet_id == wall_collision_facet_id(cc,lll)) then
338  get_collision(:) = wall_collision_pft(:,cc,lll)
339  return
340  else if (-1 == wall_collision_facet_id(cc,lll)) then
341  free_index = cc
342  endif
343  enddo
344 
345 ! Overwrite old data. This is needed because a particle moving from
346 ! one dg cell to another may no longer 'see' an STL before it moved
347 ! out of contact range. Therefore, the 'remove_collision' function
348 ! does not get called to cleanup the stale data.
349  if(-1 == free_index) then
350  dgijk=dg_pijk(lll)
351  cc_lp: do cc=1, collision_array_max
352  do lc=1, facets_at_dg(dgijk)%count
353  if(wall_collision_facet_id(cc,lll) == &
354  facets_at_dg(dgijk)%id(lc)) cycle cc_lp
355  enddo
356  free_index = cc
357  exit cc_lp
358  enddo cc_lp
359  endif
360 
361 ! Last resort... grow the collision array
362  if(-1 == free_index) then
363  free_index=collision_array_max+1
364  collision_array_max = 2*collision_array_max
365  CALL grow_wall_collision(collision_array_max)
366  endif
367 
368  wall_collision_facet_id(free_index,lll) = facet_id
369  wall_collision_pft(:,free_index,lll) = zero
370  get_collision(:) = wall_collision_pft(:,free_index,lll)
371  return
372 
373  END FUNCTION get_collision
374 
375 
376 !......................................................................!
377 ! Subroutine: GROW_WALL_COLLISION !
378 ! !
379 ! Purpose: Return the integrated (t0->t) tangential displacement. !
380 !......................................................................!
381  SUBROUTINE grow_wall_collision(NEW_SIZE)
383  use discretelement
384 
385  use stl_dbg_des, only: write_this_stl
387 
388  use error_manager
389 
390  IMPLICIT NONE
391 
392  INTEGER, INTENT(IN) :: NEW_SIZE
393  INTEGER :: lSIZE1, lSIZE2, lSIZE3
394  INTEGER, ALLOCATABLE :: tmpI2(:,:)
395  DOUBLE PRECISION, ALLOCATABLE :: tmpR3(:,:,:)
396 
397  lsize1 = size(wall_collision_facet_id,1)
398  lsize2 = size(wall_collision_facet_id,2)
399 
400  allocate(tmpi2(new_size, lsize2))
401  tmpi2(1:lsize1,:) = wall_collision_facet_id(1:lsize1,:)
402  call move_alloc(tmpi2, wall_collision_facet_id)
403  wall_collision_facet_id(lsize1+1:new_size,:) = -1
404 
405  lsize1 = size(wall_collision_pft,1)
406  lsize2 = size(wall_collision_pft,2)
407  lsize3 = size(wall_collision_pft,3)
408 
409  allocate(tmpr3(lsize1, new_size, lsize3))
410  tmpr3(:,1:lsize2,:) = wall_collision_pft(:,1:lsize2,:)
411  call move_alloc(tmpr3, wall_collision_pft)
412 
413  RETURN
414  END SUBROUTINE grow_wall_collision
415 
416 
417 
418 
419 !......................................................................!
420 ! Function: UPDATE_COLLISION !
421 ! !
422 ! Purpose: Update the integrated (t0->t) tangential displacement. !
423 !......................................................................!
424  SUBROUTINE update_collision(PFT, LLL, FACET_ID, &
425  wall_collision_facet_id, wall_collision_pft)
427  use error_manager
428  implicit none
429 
430  DOUBLE PRECISION, INTENT(IN) :: PFT(dimn)
431  INTEGER, INTENT(IN) :: LLL,FACET_ID
432  INTEGER, INTENT(IN) :: WALL_COLLISION_FACET_ID(:,:)
433  DOUBLE PRECISION, INTENT(INOUT) :: WALL_COLLISION_PFT(:,:,:)
434  INTEGER :: CC
435 
436  do cc = 1, collision_array_max
437  if (facet_id == wall_collision_facet_id(cc,lll)) then
438  wall_collision_pft(:,cc,lll) = pft(:)
439  return
440  endif
441  enddo
442 
443  CALL init_err_msg("CALC_COLLISION_WALL_MOD: UPDATE_COLLISION")
444  WRITE(err_msg, 1100)
445  CALL flush_err_msg(abort=.true.)
446 
447  1100 FORMAT('Error: COLLISION_ARRAY_MAX too small. ')
448 
449  END SUBROUTINE update_collision
450 
451 !......................................................................!
452 ! Function: REMOVE_COLLISION !
453 ! !
454 ! Purpose: Clear the integrated (t0->t) tangential displacement once !
455 ! the collision is over (contact ended). !
456 !......................................................................!
457  SUBROUTINE remove_collision(LLL,FACET_ID,WALL_COLLISION_FACET_ID)
459  use error_manager
460 
461  IMPLICIT NONE
462 
463  INTEGER, INTENT(IN) :: LLL,FACET_ID
464  INTEGER, INTENT(INOUT) :: WALL_COLLISION_FACET_ID(:,:)
465  INTEGER :: CC
466 
467  DO cc = 1, collision_array_max
468  IF (facet_id == wall_collision_facet_id(cc,lll)) THEN
469  wall_collision_facet_id(cc,lll) = -1
470  RETURN
471  ENDIF
472  ENDDO
473 
474  END SUBROUTINE remove_collision
475 
476  END SUBROUTINE calc_dem_force_with_wall_stl
477 
478 
479 !----------------------------------------------------------------------!
480 ! !
481 ! Subroutine: CFRELVEL_WALL !
482 ! !
483 ! Purpose: Calculate the normal and tangential components of the !
484 ! relative velocity between a particle and wall contact. !
485 ! !
486 ! Comments: Only the magnitude of the normal component is returned !
487 ! whereas the full tangential vector is returned. !
488 !----------------------------------------------------------------------!
489  SUBROUTINE cfrelvel_wall(LL, VRN, VRT, NORM, DIST)
491 ! Particle translational velocity
492  use discretelement, only: des_vel_new
493 ! Particle rotational velocity
494  use discretelement, only: omega_new
495 ! Spatial array size (parameter)
496  use discretelement, only: dimn
497 ! Function for calculating the cross prodcut
498  use discretelement, only: des_crossprdct
499 
500  IMPLICIT NONE
501 
502 ! Dummy arguments:
503 !---------------------------------------------------------------------//
504 ! Particle index.
505  INTEGER, INTENT(IN) :: LL
506 ! Magnitude of the total relative translational velocity.
507  DOUBLE PRECISION, INTENT(OUT):: VRN
508 ! Total relative translational velocity (vector).
509  DOUBLE PRECISION, DIMENSION(DIMN), INTENT(OUT):: VRT
510 ! Unit normal from particle center to closest point on stl (wall)
511  DOUBLE PRECISION, DIMENSION(DIMN), INTENT(IN) :: NORM
512 ! Distance between particle center and stl (wall).
513  DOUBLE PRECISION, INTENT(IN) :: DIST
514 
515 ! Local variables
516 !---------------------------------------------------------------------//
517 ! Additional relative translational motion due to rotation
518  DOUBLE PRECISION, DIMENSION(DIMN) :: V_ROT
519 ! Total relative velocity at contact point
520  DOUBLE PRECISION, DIMENSION(DIMN) :: VRELTRANS
521 
522 ! Total relative velocity + rotational contribution
523  v_rot = dist*omega_new(ll,:)
524  vreltrans(:) = des_vel_new(ll,:) + des_crossprdct(v_rot, norm)
525 
526 ! magnitude of normal component of relative velocity (scalar)
527  vrn = dot_product(vreltrans,norm)
528 
529 ! total relative translational slip velocity at the contact point
530 ! Equation (8) in Tsuji et al. 1992
531  vrt(:) = vreltrans(:) - vrn*norm(:)
532 
533  RETURN
534  END SUBROUTINE cfrelvel_wall
535 
536 
537 !----------------------------------------------------------------//
538 ! SUBROUTINE: CALC_DEM_THERMO_WITH_WALL_STL
539 ! By: Aaron M.
540 ! Purpose: Compute heat transfer to particles due to boundaries
541 !----------------------------------------------------------------//
542 
545  USE bc
546  USE compar, only: istart3, iend3, jstart3, jend3, kstart3, kend3
548  USE des_thermo
549  USE des_thermo_cond
550  USE desgrid
551  USE discretelement
552  USE exit, only: mfix_exit
553  USE functions
554  USE geometry, only: do_k, imax1, imax2, imin1, imin2
555  USE geometry, only: no_k, jmax1, jmax2, jmin1, jmin2
556  USE geometry, only: kmax1, kmax2, kmin1, kmin2, zlength
557  USE geometry, only: dx, dy, dz
559  USE param1
560  USE physprop
561  USE run, only: units, time
562  USE stl
564 
565  IMPLICIT NONE
566 
567  INTEGER :: LL ! Loop index for particle
568  INTEGER :: CELL_ID ! Desgrid cell index
569  INTEGER :: CELL_COUNT ! Loop index for facets
570  INTEGER :: IJK_FLUID ! IJK index for fluid cell
571  INTEGER :: I_FLUID, J_FLUID, K_FLUID
572  INTEGER :: I_Facet, J_Facet, K_Facet, IJK_Facet
573  INTEGER :: I1,J1,K1
574  INTEGER :: phase_LL ! Phase index for particle
575 
576  INTEGER, PARAMETER :: MAX_CONTACTS = 12
577  INTEGER :: iFacet ! loop index for facets
578  INTEGER :: count_Facets ! counter for number of facets particle contacts
579  DOUBLE PRECISION, DIMENSION(3,MAX_CONTACTS) :: NORM_FAC_CONTACT
580  LOGICAL :: USE_FACET
581  LOGICAL :: DOMAIN_BDRY
582 
583  INTEGER :: NF ! Facet ID
584  INTEGER :: AXIS ! Facet direction
585  DOUBLE PRECISION :: RLENS_SQ ! lens radius squared
586  DOUBLE PRECISION :: RLENS ! lens radius
587  DOUBLE PRECISION :: RPART ! Particle radius
588 
589  ! vectors for minimum / maximum possible particle contacts
590  DOUBLE PRECISION, DIMENSION(3) :: PARTPOS_MIN, PARTPOS_MAX
591  DOUBLE PRECISION, DIMENSION(3) :: POS_TMP ! Temp vector
592  DOUBLE PRECISION, DIMENSION(3) :: DIST, NORMAL
593 
594  DOUBLE PRECISION, DIMENSION(3) :: CLOSEST_PT
595 
596  DOUBLE PRECISION :: line_t ! Normal projection for part/wall
597  DOUBLE PRECISION :: DISTSQ ! Separation from particle and facet (squared)
598  DOUBLE PRECISION :: PROJ
599 
600  INTEGER :: BC_ID ! BC ID
601  INTEGER :: IBC ! BC Loop Index
602 
603  DOUBLE PRECISION :: TWALL
604  DOUBLE PRECISION :: K_gas
605  DOUBLE PRECISION :: TPART
606  DOUBLE PRECISION :: OVERLAP
607  DOUBLE PRECISION :: QSWALL, AREA
608 
609  LOGICAL, SAVE :: OUTPUT_WARNING = .true.
610 
611 
612 
613  ! IF(.NOT.DES_CONTINUUM_COUPLED.or.DES_EXPLICITLY_COUPLED)THEN
614  ! CALL PARTICLES_IN_CELL
615  ! ENDIF
616  DO ll = 1, max_pip
617  ! Skip non-existent particles or ghost particles
618  IF (.NOT.is_normal(ll)) cycle
619  phase_ll = pijk(ll,5)
620  IF(.NOT.calc_cond_des(phase_ll))cycle
621  ! Get desgrid cell index
622  cell_id = dg_pijk(ll)
623 
624  ! Skip cells that do not have neighboring facet
625  IF (facets_at_dg(cell_id)%COUNT <1) cycle
626 
627  ! Store lens radius of particle
628  rlens = (one+flpc)*des_radius(ll)
629  rlens_sq = rlens*rlens
630 
631  rpart = des_radius(ll)
632 
633  ! Compute max/min particle locations
634  partpos_max(:) = des_pos_new(ll,:) + rlens
635  partpos_min(:) = des_pos_new(ll,:) - rlens
636 
637  ! Get fluid cell
638  i_fluid = pijk(ll,1)
639  j_fluid = pijk(ll,2)
640  k_fluid = pijk(ll,3)
641  ijk_fluid = pijk(ll,4)
642  tpart = des_t_s(ll)
643 
644  ! Sometimes PIJK is not updated every solids timestep and
645  ! therefore doesn't give the correct fluid cell that
646  ! contains the particles. If so, determine actual fluid
647  ! cell that contains the particle
648  IF(.NOT.des_continuum_coupled.or.des_explicitly_coupled)THEN
649  IF(i_fluid <= istart3 .OR. i_fluid >= iend3) THEN
650  CALL pic_search(i_fluid, des_pos_new(ll,1), xe, &
651  dimension_i, imin2, imax2)
652  ELSE
653  IF((des_pos_new(ll,1) >= xe(i_fluid-1)) .AND. &
654  (des_pos_new(ll,1) < xe(i_fluid))) THEN
655  i_fluid = i_fluid
656  ELSEIF((des_pos_new(ll,1) >= xe(i_fluid)) .AND. &
657  (des_pos_new(ll,1) < xe(i_fluid+1))) THEN
658  i_fluid = i_fluid+1
659  ELSEIF((des_pos_new(ll,1) >= xe(i_fluid-2)) .AND. &
660  (des_pos_new(ll,1) < xe(i_fluid-1))) THEN
661  i_fluid = i_fluid-1
662  ELSE
663  CALL pic_search(i_fluid, des_pos_new(ll,1), xe, &
664  dimension_i, imin2, imax2)
665  ENDIF
666  ENDIF !(I)
667  IF(j_fluid <= jstart3 .OR. j_fluid >= jend3) THEN
668  CALL pic_search(j_fluid, des_pos_new(ll,2), yn, &
669  dimension_j, jmin2, jmax2)
670  ELSE
671  IF((des_pos_new(ll,2) >= yn(j_fluid-1)) .AND. &
672  (des_pos_new(ll,2) < yn(j_fluid))) THEN
673  j_fluid = j_fluid
674  ELSEIF((des_pos_new(ll,2) >= yn(j_fluid)) .AND. &
675  (des_pos_new(ll,2) < yn(j_fluid+1))) THEN
676  j_fluid = j_fluid+1
677  ELSEIF((des_pos_new(ll,2) >= yn(j_fluid-2)) .AND. &
678  (des_pos_new(ll,2) < yn(j_fluid-1))) THEN
679  j_fluid = j_fluid-1
680  ELSE
681  CALL pic_search(j_fluid, des_pos_new(ll,2), yn, &
682  dimension_j, jmin2, jmax2)
683  ENDIF
684  ENDIF !(J)
685 
686  IF(no_k) THEN
687  k_fluid = 1
688  ELSE
689  IF(k_fluid <= kstart3 .OR. k_fluid >= kend3) THEN
690  CALL pic_search(k_fluid, des_pos_new(ll,3), zt, &
691  dimension_k, kmin2, kmax2)
692  ELSE
693  IF((des_pos_new(ll,3) >= zt(k_fluid-1)) .AND. &
694  (des_pos_new(ll,3) < zt(k_fluid))) THEN
695  k_fluid = k_fluid
696  ELSEIF((des_pos_new(ll,3) >= zt(k_fluid)) .AND. &
697  (des_pos_new(ll,3) < zt(k_fluid+1))) THEN
698  k_fluid = k_fluid+1
699  ELSEIF((des_pos_new(ll,3) >= zt(k_fluid-2)) .AND. &
700  (des_pos_new(ll,3) < zt(k_fluid-1))) THEN
701  k_fluid = k_fluid-1
702  ELSE
703  CALL pic_search(k_fluid, des_pos_new(ll,3), zt, &
704  dimension_k, kmin2, kmax2)
705  ENDIF
706  ENDIF
707  ENDIF !(K)
708  ijk_fluid = pijk(ll,4)
709  ENDIF ! (NOT CONTINUUM_COUPLED OR EXPLICIT)
710 
711 
712 ! Initialize counter for number of facets
713  count_facets = 0
714 
715  ! Loop over potential facets
716  DO cell_count = 1, facets_at_dg(cell_id)%count
717  ! Get direction (axis) and facet id (NF)
718  axis = facets_at_dg(cell_id)%dir(cell_count)
719  nf = facets_at_dg(cell_id)%id(cell_count)
720 
721  ! Check to see if facet is out of reach of particle
722  if (facets_at_dg(cell_id)%min(cell_count) > &
723  partpos_max(axis)) then
724  cycle
725  endif
726  if (facets_at_dg(cell_id)%max(cell_count) < &
727  partpos_min(axis)) then
728  cycle
729  endif
730 
731  ! Compute projection (normal distance) from wall to particle
732  line_t = dot_product(vertex(1,:,nf) - des_pos_new(ll,:),&
733  & norm_face(:,nf))
734 
735  ! If normal exceeds particle radius, particle is not in contact
736  if((line_t.lt.-rlens))cycle
737 
738  ! Compute closest point on facet
739  pos_tmp(:) = des_pos_new(ll,:)
740  CALL closestptpointtriangle(pos_tmp, vertex(:,:,nf), &
741  & closest_pt(:))
742  ! Compute position vector from particle to closest point on facet
743  dist(:) = closest_pt(:)-pos_tmp(:)
744  distsq = dot_product(dist,dist)
745 
746  ! Skip particles that are more than lens radius from facet
747  IF(distsq .GE. (rlens_sq-small_number))cycle
748 
749  ! Only do heat transfer for particles that are directly above facet
750  ! Heat transfer routines not generalized for edge contacts, but
751  ! those should normally yield negligible heat transfer contributions
752 
753  ! Normalize distance vector and compare to facet normal
754  normal(:)=-dist(:)/sqrt(distsq)
755  proj = sqrt(abs(dot_product(normal, norm_face(:,nf))))
756  IF(abs(one-proj).gt.1.0d-6)cycle
757 
758  ! Get overlap
759  overlap = rpart - sqrt(distsq)
760 
761  ! Initialize area for facet (for post-proc. flux)
762  area = zero
763 
764  ! Initialize BDRY FLAG
765  domain_bdry = .false.
766  ! Get BC_ID
767  bc_id = bc_id_stl_face(nf)
768 
769  ! BC_ID is set to 0 in pre-proc if stl is a domain boundary
770  IF(bc_id.eq.0)then
771  i1=i_fluid
772  j1=j_fluid
773  k1=k_fluid
774  domain_bdry = .true.
775 
776  ! Domain boundary, figure out real boundary ID
777  IF(norm_face(1,nf).ge.0.9999)THEN
778  ! WEST face
779  i1=imin2
780  IF(do_k)THEN
781  area = dy(j_fluid)*dz(k_fluid)
782  ELSE
783  area = dy(j_fluid)*zlength
784  ENDIF
785  ELSEIF(norm_face(1,nf).le.-0.9999)THEN
786  ! EAST FACE
787  i1=imax2
788  IF(do_k)THEN
789  area = dy(j_fluid)*dz(k_fluid)
790  ELSE
791  area = dy(j_fluid)*zlength
792  ENDIF
793  ELSEIF(norm_face(2,nf).ge.0.9999)THEN
794  ! SOUTH FACE
795  j1=jmin2
796  IF(do_k)THEN
797  area = dx(i_fluid)*dz(k_fluid)
798  ELSE
799  area = dx(i_fluid)*zlength
800  ENDIF
801  ELSEIF(norm_face(2,nf).le.-0.9999)THEN
802  ! NORTH FACE
803  j1=jmax2
804  IF(do_k)THEN
805  area = dx(i_fluid)*dz(k_fluid)
806  ELSE
807  area = dx(i_fluid)*zlength
808  ENDIF
809  ELSEIF(norm_face(3,nf).ge.0.9999)THEN
810  ! BOTTOM FACE
811  k1=kmin2
812  area = dx(i_fluid)*dy(j_fluid)
813 
814  ELSEIF(norm_face(3,nf).le.-0.9999)THEN
815  ! TOP FACE
816  k1=kmax2
817  area = dx(i_fluid)*dy(j_fluid)
818  ELSE
819  WRITE( *,*)'PROBLEM, COULD NOT FIND DOMAIN BOUNDARY'
820  WRITE(*,*)' In calc_thermo_des_wall_stl'
821  call mfix_exit(1)
822 
823  ENDIF
824 
825 
826  ! Loop through defined BCs to see which one particle neighbors
827  DO ibc = 1, dimension_bc
828  IF(.NOT.bc_defined(ibc))cycle
829  IF (i1.ge.bc_i_w(ibc).and.i1.le.bc_i_e(ibc).and.&
830  j1.ge.bc_j_s(ibc).and.j1.le.bc_j_n(ibc).and.&
831  k1.ge.bc_k_b(ibc).and.k1.le.bc_k_t(ibc))THEN
832  bc_id = ibc
833  exit
834  ENDIF
835  ENDDO
836  IF(bc_id.eq.0)then
837  IF(output_warning)THEN
838  write(*,*)'WARNING: Could not find BC'
839  write(*,*)'Check input deck to make sure domain boundaries &
840  are defined'
841  write(*,*)'SUPPRESSING FUTURE OUTPUT'
842  write(*,*)'DES_POS_NEW'
843  write(*,'(3(F12.5, 3X))')(des_pos_new(ll,ibc),ibc=1,3)
844  write(*,*)'I,J,K'
845  write(*,*)i1,j1,k1
846  write(*,*)'CLOSEST PT'
847  write(*,'(3(F12.5, 3X))')(closest_pt(ibc),ibc=1,3)
848  write(*,*)'NORM_FACE'
849  write(*,'(3(F12.5, 3X))')(norm_face(ibc,nf),ibc=1,3)
850  output_warning = .false.
851  ENDIF
852  cycle !
853  ENDIF
854 
855  ENDIF !Domain Boundary (facet ID was 0)
856 
857  IF (bc_type_enum(bc_id) == no_slip_wall .OR. &
858  bc_type_enum(bc_id) == free_slip_wall .OR. &
859  bc_type_enum(bc_id) == par_slip_wall .OR. &
860  bc_type_enum(bc_id) == cg_nsw .OR. &
861  bc_type_enum(bc_id) == cg_fsw .OR. &
862  bc_type_enum(bc_id) == cg_psw) THEN
863 
864 
865 
866  ! CHECK TO MAKE SURE FACET IS UNIQUE
867  use_facet=.true.
868  DO ifacet=1,count_facets
869  ! DO CHECK BY ENSURING NORMAL VECTOR IS NEARLY PARALLEL
870  proj = sqrt(abs(dot_product(normal, norm_fac_contact(:,ifacet))))
871  IF(abs(one-proj).gt.1.0d-6)THEN
872  use_facet=.false.
873  EXIT
874  ENDIF
875  ENDDO
876  IF(.NOT.use_facet)cycle
877 
878  ! FACET IS UNIQUE
879  count_facets=count_facets+1
880  norm_fac_contact(:,count_facets)=normal(:)
881 
882 ! Do heat transfer
883  ! GET WALL TEMPERATURE
884  twall = bc_tw_s(bc_id,phase_ll)
885 
886  ! GET GAS THERMAL CONDUCTIVITY
887  if(k_g0.eq.undefined)then
888  ! Compute gas conductivity as is done in calc_k_g
889  ! But use average of particle and wall temperature to be gas temperature
890 
891  k_gas = 6.02d-5*sqrt(half*(twall+tpart)/300.d0) ! cal/(s.cm.K)
892  ! 1 cal = 4.183925D0 J
893  IF (units == 'SI') k_gas = 418.3925d0*k_gas !J/s.m.K
894  else
895  k_gas=k_g0
896  endif
897  IF(twall.eq.undefined)cycle
898  qswall = des_conduction_wall(overlap,k_s0(phase_ll), &
899  & k_s0(phase_ll),k_gas,twall, tpart, rpart, &
900  & rlens, phase_ll)
901 
902 
903  q_source(ll) = q_source(ll)+qswall
904 
905  ! BELOW CODE IS ONLY NECESSARY FOR OUTPUTING
906  ! DATA. Need to know fluid cell that contact
907  ! point resides in so that wall flux can be
908  ! output correctly.
909 
910  i_facet = i_fluid
911  j_facet = j_fluid
912  k_facet = k_fluid
913 
914  ! This checks to see if the contact point was NOT on a domain boundary
915 
916  IF(.NOT.domain_bdry)THEN
917  IF(closest_pt(1) >= xe(i_fluid))THEN
918  i_facet = min(imax1, i_fluid+1)
919  ELSEIF(closest_pt(1) < xe(i_fluid-1))THEN
920  i_facet = max(imin1, i_fluid-1)
921  ENDIF
922 
923  IF(closest_pt(2) >= yn(j_fluid))THEN
924  j_facet = min(jmax1, j_fluid+1)
925  ELSEIF(closest_pt(2) < yn(j_fluid-1))THEN
926  j_facet = max(jmin1, j_fluid-1)
927  ENDIF
928  IF(do_k)THEN
929  IF(closest_pt(3) >= zt(k_fluid))THEN
930  k_facet = min(kmax1, k_fluid+1)
931  ELSEIF(closest_pt(3) < zt(k_fluid-1))THEN
932  k_facet = max(kmin1, k_fluid-1)
933  ENDIF
934  ENDIF
935  ijk_facet=funijk(i_facet,j_facet,k_facet)
936  area=area_cut(ijk_facet)
937 
938  ! AREA is left undefined if contact was with cut-cell surface
939  IF (area.eq.zero)then
940  i_facet = i_fluid
941  j_facet = j_fluid
942  k_facet = k_fluid
943  ijk_facet=funijk(i_facet,j_facet,k_facet)
944  IF(norm_face(1,nf).ge.0.9999)THEN
945  ! WEST face
946  IF(do_k)THEN
947  area = dy(j_facet)*dz(k_facet)
948  ELSE
949  area = dy(j_facet)*zlength
950  ENDIF
951  ELSEIF(norm_face(1,nf).le.-0.9999)THEN
952  ! EAST FACE
953  IF(do_k)THEN
954  area = dy(j_facet)*dz(k_facet)
955  ELSE
956  area = dy(j_facet)*zlength
957  ENDIF
958  ELSEIF(norm_face(2,nf).ge.0.9999)THEN
959  ! SOUTH FACE
960  IF(do_k)THEN
961  area = dx(i_facet)*dz(k_facet)
962  ELSE
963  area = dx(i_facet)*zlength
964  ENDIF
965  ELSEIF(norm_face(2,nf).le.-0.9999)THEN
966  ! NORTH FACE
967  IF(do_k)THEN
968  area = dx(i_facet)*dz(k_facet)
969  ELSE
970  area = dx(i_facet)*zlength
971  ENDIF
972  ELSEIF(norm_face(3,nf).ge.0.9999)THEN
973  ! BOTTOM FACE
974  area = dx(i_facet)*dy(j_facet)
975  ELSEIF(norm_face(3,nf).le.-0.9999)THEN
976  ! TOP FACE
977  area = dx(i_facet)*dy(j_facet)
978  ENDIF
979  ENDIF ! Area==0 (because cut-cell facet exists in non cut-cell)
980  ENDIF ! NOT DOMAIN_BDRY
981  ijk_facet = funijk(i_facet,j_facet,k_facet)
982  ! AM error check
983  IF(.NOT.fluid_at(ijk_facet).AND. &
984  & .NOT.blocked_cell_at(ijk_facet))THEN
985  write(*,*)'ERROR: Cell containing facet is not a fluid &
986  & cell or a blocked cell'
987  write(*,*)fluid_at(ijk_facet), blocked_cell_at(ijk_facet)
988  write(*,*)'PART POS',(des_pos_new(ll,ibc),ibc=1,3)
989  write(*,*)'FACET NORM',(norm_face(ibc,nf),ibc=1,3)
990  write(*,*)'BC_ID', bc_id
991  write(*,*)'I,J,K (Facet)', i_facet,j_facet,k_facet
992 
993  call mfix_exit(1)
994  ENDIF
995 
996  IF(fluid_at(ijk_facet))THEN
997  des_qw_cond(ijk_facet,phase_ll) = &
998  des_qw_cond(ijk_facet, phase_ll) + qswall/area
999  ENDIF
1000 
1001  ENDIF ! WALL BDRY
1002  ENDDO ! CELL_COUNT (facets)
1003  ENDDO ! LL
1004  RETURN
1005 
1006  END SUBROUTINE calc_dem_thermo_with_wall_stl
1007 
1008  end module calc_collision_wall
integer, dimension(dimension_bc) bc_k_b
Definition: bc_mod.f:70
integer dimension_i
Definition: param_mod.f:7
integer iend3
Definition: compar_mod.f:80
type(facets_to_dg), dimension(:), allocatable facets_at_dg
Definition: stl_mod.f:76
integer imax2
Definition: geometry_mod.f:61
subroutine closestptpointtriangle(pointp, points, closest_point)
integer jstart3
Definition: compar_mod.f:80
double precision, dimension(:), allocatable des_t_s
double precision, parameter one
Definition: param1_mod.f:29
double precision, dimension(3, 3, dim_stl) vertex
Definition: stl_mod.f:20
logical, dimension(dim_m) calc_cond_des
integer dimension_k
Definition: param_mod.f:9
double precision flpc
integer, dimension(dimension_bc) bc_i_w
Definition: bc_mod.f:54
integer, dimension(dimension_bc) bc_j_n
Definition: bc_mod.f:66
double precision, dimension(dimension_bc, dim_m) bc_tw_s
Definition: bc_mod.f:341
logical, dimension(:), allocatable small_cell_at
Definition: cutcell_mod.f:360
double precision, dimension(0:dim_j) dy
Definition: geometry_mod.f:70
integer kstart3
Definition: compar_mod.f:80
integer, dimension(dimension_bc) bc_type_enum
Definition: bc_mod.f:146
double precision, parameter undefined
Definition: param1_mod.f:18
double precision, dimension(0:dim_k) dz
Definition: geometry_mod.f:72
integer jmin2
Definition: geometry_mod.f:89
integer, dimension(dim_stl) bc_id_stl_face
Definition: stl_mod.f:51
integer kend3
Definition: compar_mod.f:80
subroutine init_err_msg(CALLER)
integer kmax1
Definition: geometry_mod.f:58
subroutine mfix_exit(myID, normal_termination)
Definition: exit.f:5
integer, dimension(dimension_bc) bc_k_t
Definition: bc_mod.f:74
subroutine write_this_stl(this)
subroutine, public calc_dem_thermo_with_wall_stl
integer imax1
Definition: geometry_mod.f:54
integer jend3
Definition: compar_mod.f:80
integer jmax2
Definition: geometry_mod.f:63
double precision, parameter small_number
Definition: param1_mod.f:24
Definition: stl_mod.f:1
integer, dimension(dimension_bc) bc_j_s
Definition: bc_mod.f:62
Definition: exit.f:2
subroutine remove_collision(LLL, FACET_ID, WALL_COLLISION_FACET_ID)
double precision, dimension(dim_m) k_s0
Definition: physprop_mod.f:95
double precision, dimension(3, dim_stl) norm_face
Definition: stl_mod.f:22
logical, dimension(dimension_bc) bc_defined
Definition: bc_mod.f:207
double precision, dimension(0:dim_i) dx
Definition: geometry_mod.f:68
integer kmax2
Definition: geometry_mod.f:65
subroutine update_collision(PFT, LLL, FACET_ID, WALL_COLLISION_FACET_ID, WALL_COLLISION_PFT)
double precision, parameter half
Definition: param1_mod.f:28
integer jmax1
Definition: geometry_mod.f:56
Definition: run_mod.f:13
double precision k_g0
Definition: physprop_mod.f:89
Definition: param_mod.f:2
character(len=16) units
Definition: run_mod.f:30
logical no_k
Definition: geometry_mod.f:28
integer jmin1
Definition: geometry_mod.f:42
logical do_k
Definition: geometry_mod.f:30
logical, dimension(:), allocatable cut_cell_at
Definition: cutcell_mod.f:355
double precision function des_conduction_wall(OLAP, K_sol, K_wall, K_gas, TWall, TPart, Rpart, RLens, M)
double precision, dimension(:), allocatable area_cut
Definition: cutcell_mod.f:131
subroutine pic_search(IDX, lPOS, ENT_POS, lDIMN, lSTART, lEND)
character(len=line_length), dimension(line_count) err_msg
integer imin2
Definition: geometry_mod.f:89
double precision, dimension(:), allocatable q_source
double precision, dimension(:,:), allocatable des_qw_cond
double precision function, dimension(dimn) get_collision(LLL, FACET_ID, WALL_COLLISION_FACET_ID, WALL_COLLISION_PFT)
subroutine write_stls_this_dg(DG, STL_TYPE)
subroutine grow_wall_collision(NEW_SIZE)
subroutine, public calc_dem_force_with_wall_stl
double precision, parameter pi
Definition: constant_mod.f:158
logical, dimension(:), allocatable blocked_cell_at
Definition: cutcell_mod.f:361
integer imin1
Definition: geometry_mod.f:40
double precision time
Definition: run_mod.f:45
integer istart3
Definition: compar_mod.f:80
integer kmin1
Definition: geometry_mod.f:44
integer, dimension(dimension_bc) bc_i_e
Definition: bc_mod.f:58
double precision, parameter zero
Definition: param1_mod.f:27
double precision zlength
Definition: geometry_mod.f:37
subroutine flush_err_msg(DEBUG, HEADER, FOOTER, ABORT, LOG, CALL_TREE)
Definition: bc_mod.f:23
subroutine cfrelvel_wall(LL, VRN, VRT, NORM, DIST)
integer kmin2
Definition: geometry_mod.f:89
integer dimension_j
Definition: param_mod.f:8