@@ -95,13 +95,15 @@ contains
9595 integer :: i, j, k
9696 integer :: max_num_gps, max_num_inner_gps
9797
98+ ! do all set up for moving immersed boundaries
9899 moving_immersed_boundary_flag = .false.
99100 do i = 1 , num_ibs
100101 if (patch_ib(i)%moving_ibm /= 0 ) then
101102 call s_compute_moment_of_inertia(i, patch_ib(i)%angular_vel)
102103 moving_immersed_boundary_flag = .true.
103104 end if
104105 call s_update_ib_rotation_matrix(i)
106+ call s_compute_centroid_offset(i)
105107 end do
106108 $:GPU_ENTER_DATA(copyin= ' [patch_ib]' )
107109
@@ -1012,24 +1014,35 @@ contains
10121014 ! compute the surface integrals of the IB via a volume integraion method described in
10131015 ! "A coupled IBM/Euler-Lagrange framework for simulating shock-induced particle size segregation"
10141016 ! by Archana Sridhar and Jesse Capecelatro
1015- subroutine s_compute_ib_forces(q_prim_vf, dynamic_viscosity )
1017+ subroutine s_compute_ib_forces(q_prim_vf, fluid_pp )
10161018
10171019 ! real(wp), dimension(idwbuff(1)%beg:idwbuff(1)%end, &
10181020 ! idwbuff(2)%beg:idwbuff(2)%end, &
10191021 ! idwbuff(3)%beg:idwbuff(3)%end), intent(in) :: pressure
10201022 type(scalar_field), dimension(1:sys_size), intent(in) :: q_prim_vf
1021- real(wp ), intent(in) :: dynamic_viscosity
1023+ type(physical_parameters ), dimension(1:num_fluids), intent(in) :: fluid_pp
10221024
1023- integer :: gp_id, i, j, k, l, q, ib_idx
1025+ integer :: gp_id, i, j, k, l, q, ib_idx, fluid_idx
10241026 real(wp), dimension(num_ibs, 3) :: forces, torques
10251027 real(wp), dimension(1:3, 1:3) :: viscous_stress_div, viscous_stress_div_1, viscous_stress_div_2, viscous_cross_1, viscous_cross_2 ! viscous stress tensor with temp vectors to hold divergence calculations
10261028 real(wp), dimension(1:3) :: local_force_contribution, radial_vector, local_torque_contribution, vel
1027- real(wp) :: cell_volume, dx, dy, dz
1029+ real(wp) :: cell_volume, dx, dy, dz, dynamic_viscosity
1030+ real(wp), dimension(1:num_fluids) :: dynamic_viscosities
10281031
10291032 forces = 0._wp
10301033 torques = 0._wp
10311034
1032- $:GPU_PARALLEL_LOOP(private=' [ib_idx,radial_vector,local_force_contribution,cell_volume,local_torque_contribution, viscous_stress_div, viscous_stress_div_1, viscous_stress_div_2, viscous_cross_1, viscous_cross_2, dx, dy, dz]' , copy=' [forces,torques]' , copyin=' [ib_markers,patch_ib,dynamic_viscosity]' , collapse=3)
1035+ if (viscous) then
1036+ do fluid_idx = 1, num_fluids
1037+ if (fluid_pp(fluid_idx)%Re(1) /= 0._wp) then
1038+ dynamic_viscosities(fluid_idx) = 1._wp/fluid_pp(fluid_idx)%Re(1)
1039+ else
1040+ dynamic_viscosities(fluid_idx) = 0._wp
1041+ end if
1042+ end do
1043+ end if
1044+
1045+ $:GPU_PARALLEL_LOOP(private=' [ib_idx,fluid_idx, radial_vector,local_force_contribution,cell_volume,local_torque_contribution, dynamic_viscosity, viscous_stress_div, viscous_stress_div_1, viscous_stress_div_2, viscous_cross_1, viscous_cross_2, dx, dy, dz]' , copy=' [forces,torques]' , copyin=' [ib_markers,patch_ib,dynamic_viscosities]' , collapse=3)
10331046 do i = 0, m
10341047 do j = 0, n
10351048 do k = 0, p
@@ -1044,26 +1057,33 @@ contains
10441057 dx = x_cc(i + 1) - x_cc(i)
10451058 dy = y_cc(j + 1) - y_cc(j)
10461059
1047- ! Get the pressure contribution to force via a finite difference to compute the 2D components of the gradient of the pressure and cell volume
1048- local_force_contribution(1) = -1._wp*(q_prim_vf(E_idx)%sf(i + 1, j, k) - q_prim_vf(E_idx)%sf(i - 1, j, k))/(2._wp*dx) ! force is the negative pressure gradient
1049- local_force_contribution(2) = -1._wp*(q_prim_vf(E_idx)%sf(i, j + 1, k) - q_prim_vf(E_idx)%sf(i, j - 1, k))/(2._wp*dy)
1050- cell_volume = abs(dx*dy)
1051- ! add the 3D component of the pressure gradient, if we are working in 3 dimensions
1052- if (num_dims == 3) then
1053- dz = z_cc(k + 1) - z_cc(k)
1054- local_force_contribution(3) = -1._wp*(q_prim_vf(E_idx)%sf(i, j, k + 1) - q_prim_vf(E_idx)%sf(i, j, k - 1))/(2._wp*dz)
1055- cell_volume = abs(cell_volume*dz)
1056- else
1057- local_force_contribution(3) = 0._wp
1058- end if
1060+ local_force_contribution(:) = 0._wp
1061+ do fluid_idx = 0, num_fluids - 1
1062+ ! Get the pressure contribution to force via a finite difference to compute the 2D components of the gradient of the pressure and cell volume
1063+ local_force_contribution(1) = local_force_contribution(1) - (q_prim_vf(E_idx + fluid_idx)%sf(i + 1, j, k) - q_prim_vf(E_idx + fluid_idx)%sf(i - 1, j, k))/(2._wp*dx) ! force is the negative pressure gradient
1064+ local_force_contribution(2) = local_force_contribution(2) - (q_prim_vf(E_idx + fluid_idx)%sf(i, j + 1, k) - q_prim_vf(E_idx + fluid_idx)%sf(i, j - 1, k))/(2._wp*dy)
1065+ cell_volume = abs(dx*dy)
1066+ ! add the 3D component of the pressure gradient, if we are working in 3 dimensions
1067+ if (num_dims == 3) then
1068+ dz = z_cc(k + 1) - z_cc(k)
1069+ local_force_contribution(3) = local_force_contribution(3) - (q_prim_vf(E_idx + fluid_idx)%sf(i, j, k + 1) - q_prim_vf(E_idx + fluid_idx)%sf(i, j, k - 1))/(2._wp*dz)
1070+ cell_volume = abs(cell_volume*dz)
1071+ end if
1072+ end do
10591073
10601074 ! Update the force values atomically to prevent race conditions
10611075 call s_cross_product(radial_vector, local_force_contribution, local_torque_contribution)
10621076
10631077 ! get the viscous stress and add its contribution if that is considered
10641078 ! TODO :: This is really bad code
1065- ! if (.false.) then
10661079 if (viscous) then
1080+ ! compute the volume-weighted local dynamic viscosity
1081+ dynamic_viscosity = 0._wp
1082+ do fluid_idx = 1, num_fluids
1083+ ! local dynamic viscosity is the dynamic viscosity of the fluid times alpha of the fluid
1084+ dynamic_viscosity = dynamic_viscosity + (q_prim_vf(fluid_idx + advxb - 1)%sf(i, j, k)*dynamic_viscosities(fluid_idx))
1085+ end do
1086+
10671087 ! get the linear force component first
10681088 call s_compute_viscous_stress_tensor(viscous_stress_div_1, q_prim_vf, dynamic_viscosity, i - 1, j, k)
10691089 call s_compute_viscous_stress_tensor(viscous_stress_div_2, q_prim_vf, dynamic_viscosity, i + 1, j, k)
@@ -1150,6 +1170,64 @@ contains
11501170
11511171 end subroutine s_finalize_ibm_module
11521172
1173+ !> Computes the center of mass for IB patch types where we are unable to determine their center of mass analytically.
1174+ !> These patches include things like NACA airfoils and STL models
1175+ subroutine s_compute_centroid_offset(ib_marker)
1176+
1177+ integer, intent(in) :: ib_marker
1178+
1179+ integer :: i, j, k, num_cells, num_cells_local
1180+ real(wp), dimension(1:3) :: center_of_mass, center_of_mass_local
1181+
1182+ ! Offset only needs to be computes for specific geometries
1183+ if (patch_ib(ib_marker)%geometry == 4 .or. &
1184+ patch_ib(ib_marker)%geometry == 5 .or. &
1185+ patch_ib(ib_marker)%geometry == 11 .or. &
1186+ patch_ib(ib_marker)%geometry == 12) then
1187+
1188+ center_of_mass_local = [0._wp, 0._wp, 0._wp]
1189+ num_cells_local = 0
1190+
1191+ ! get the summed mass distribution and number of cells to divide by
1192+ do i = 0, m
1193+ do j = 0, n
1194+ do k = 0, p
1195+ if (ib_markers%sf(i, j, k) == ib_marker) then
1196+ num_cells_local = num_cells_local + 1
1197+ center_of_mass_local = center_of_mass_local + [x_cc(i), y_cc(j), 0._wp]
1198+ if (num_dims == 3) center_of_mass_local(3) = center_of_mass_local(3) + z_cc(k)
1199+ end if
1200+ end do
1201+ end do
1202+ end do
1203+
1204+ ! reduce the mass contribution over all MPI ranks and compute COM
1205+ call s_mpi_allreduce_integer_sum(num_cells_local, num_cells)
1206+ if (num_cells /= 0) then
1207+ call s_mpi_allreduce_sum(center_of_mass_local(1), center_of_mass(1))
1208+ call s_mpi_allreduce_sum(center_of_mass_local(2), center_of_mass(2))
1209+ call s_mpi_allreduce_sum(center_of_mass_local(3), center_of_mass(3))
1210+ center_of_mass = center_of_mass/real(num_cells, wp)
1211+ else
1212+ patch_ib(ib_marker)%centroid_offset = [0._wp, 0._wp, 0._wp]
1213+ return
1214+ end if
1215+
1216+ ! assign the centroid offset as a vector pointing from the true COM to the "centroid" in the input file and replace the current centroid
1217+ patch_ib(ib_marker)%centroid_offset = [patch_ib(ib_marker)%x_centroid, patch_ib(ib_marker)%y_centroid, patch_ib(ib_marker)%z_centroid] &
1218+ - center_of_mass
1219+ patch_ib(ib_marker)%x_centroid = center_of_mass(1)
1220+ patch_ib(ib_marker)%y_centroid = center_of_mass(2)
1221+ patch_ib(ib_marker)%z_centroid = center_of_mass(3)
1222+
1223+ ! rotate the centroid offset back into the local coords of the IB
1224+ patch_ib(ib_marker)%centroid_offset = matmul(patch_ib(ib_marker)%rotation_matrix_inverse, patch_ib(ib_marker)%centroid_offset)
1225+ else
1226+ patch_ib(ib_marker)%centroid_offset(:) = [0._wp, 0._wp, 0._wp]
1227+ end if
1228+
1229+ end subroutine s_compute_centroid_offset
1230+
11531231 subroutine s_compute_moment_of_inertia(ib_marker, axis)
11541232
11551233 real(wp), dimension(3), intent(in) :: axis !< the axis about which we compute the moment. Only required in 3D.
0 commit comments