forked from MFlowCode/MFC
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathm_patch_geometries.fpp
More file actions
188 lines (139 loc) · 7.68 KB
/
Copy pathm_patch_geometries.fpp
File metadata and controls
188 lines (139 loc) · 7.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
!>
!! @file
!! @brief Contains module m_ibm
#:include 'macros.fpp'
!> @brief Contains helper functions specific to various patch gemoetries for determining if a grid cell lies inside of or outside of
!! a patch geometry
module m_patch_geometries
use m_derived_types
use m_global_parameters
use m_variables_conversion
use m_helper
use m_helper_basic
use m_constants
use m_model
implicit none
public :: f_is_inside_sphere, f_is_inside_cylinder, f_is_inside_cuboid, f_is_inside_airfoil, f_is_inside_ellipse, &
& s_compute_rotation_matrix
contains
!> Check if the x, y, and z coordinates would be located inside a sphere with the patch_id's radius
function f_is_inside_sphere(x, y, z, radius) result(is_inside)
$:GPU_ROUTINE(parallelism='[seq]')
real(wp), intent(in) :: radius, x, y, z
logical :: is_inside
is_inside = x**2 + y**2 + z**2 <= radius**2
end function f_is_inside_sphere
!> Check which length of the cylinder is not default. Use that direction as the height and the other two coordinate
! values as the radius check
function f_is_inside_cylinder(polar_x, polar_y, height, radius, length) result(is_inside)
$:GPU_ROUTINE(parallelism='[seq]')
real(wp), intent(in) :: polar_x, polar_y, height, radius, length
logical :: is_inside
! check if the circular component of the cylinder is correct
is_inside = polar_x**2 + polar_y**2 <= radius**2
! in 3D, also check the length of the cylinder
if (num_dims == 3) is_inside = is_inside .and. -0.5_wp*length <= height .and. 0.5_wp*length >= height
end function f_is_inside_cylinder
!> Check if the x, y, and possibly z coordinates would be located inside a cuboid with the patch_id's lengths
function f_is_inside_cuboid(x, y, z, length) result(is_inside)
$:GPU_ROUTINE(parallelism='[seq]')
real(wp), intent(in) :: x, y, z
real(wp), dimension(3), intent(in) :: length
logical :: is_inside
! check if x and y are inside the rectangle plane at z=0
is_inside = -0.5_wp*length(1) <= x .and. 0.5_wp*length(1) >= x .and. -0.5_wp*length(2) <= y .and. 0.5_wp*length(2) >= y
! if we are in 3D, this is a cuboid and so we must also check the z axis
if (num_dims == 3) is_inside = is_inside .and. -0.5_wp*length(3) <= z .and. 0.5_wp*length(3) >= z
end function f_is_inside_cuboid
!> Check if the x, y, are bounded by a NACA airfoil. Check if the z coordinate is inside the left and right edges of the
!! airfoil, if set.
function f_is_inside_airfoil(x, y, z, length, airfoil_id) result(is_inside)
$:GPU_ROUTINE(parallelism='[seq]')
real(wp), intent(in) :: x, y, z, length
integer, intent(in) :: airfoil_id
logical :: is_inside
integer :: k
real(wp) :: f
is_inside = .false.
! check the initial x bounds of the grid cell
if (.not. (x >= 0._wp .and. x <= ib_airfoil(airfoil_id)%c)) return
! if we are in 3D, we must also check the z axis
if (num_dims == 3 .and. (.not. (-0.5_wp*length <= z .and. 0.5_wp*length >= z))) return
! our check branches for the upper and lower half of the airfoil
if (y >= 0._wp) then
! increment the iterator so we know where in the airfoil arrays to look
k = 1
do while (ib_airfoil_grids(airfoil_id)%upper(k)%x < x)
k = k + 1
end do
! If the values are approximately equivalent, skip the next check
if (f_approx_equal(ib_airfoil_grids(airfoil_id)%upper(k)%x, x)) then
if (y <= ib_airfoil_grids(airfoil_id)%upper(k)%y) is_inside = .true.
else
! check if the y value is below the upper edge of the airfoil
f = (ib_airfoil_grids(airfoil_id)%upper(k)%x - x)/(ib_airfoil_grids(airfoil_id)%upper(k)%x &
& - ib_airfoil_grids(airfoil_id)%upper(k - 1)%x)
if (y <= ((1._wp - f)*ib_airfoil_grids(airfoil_id)%upper(k)%y + f*ib_airfoil_grids(airfoil_id)%upper(k - 1)%y)) &
& is_inside = .true.
end if
else
! increment the iterator so we know where in the airfoil arrays to look
k = 1
do while (ib_airfoil_grids(airfoil_id)%lower(k)%x < x)
k = k + 1
end do
! If the values are approximately equivalent, skip the next check
if (f_approx_equal(ib_airfoil_grids(airfoil_id)%lower(k)%x, x)) then
if (y >= ib_airfoil_grids(airfoil_id)%lower(k)%y) is_inside = .true.
else
! check if the y value is above the lower edge of the airfoil
f = (ib_airfoil_grids(airfoil_id)%lower(k)%x - x)/(ib_airfoil_grids(airfoil_id)%lower(k)%x &
& - ib_airfoil_grids(airfoil_id)%lower(k - 1)%x)
if (y >= ((1._wp - f)*ib_airfoil_grids(airfoil_id)%lower(k)%y + f*ib_airfoil_grids(airfoil_id)%lower(k - 1)%y)) &
& is_inside = .true.
end if
end if
end function f_is_inside_airfoil
function f_is_inside_ellipse(x, y, length) result(is_inside)
$:GPU_ROUTINE(parallelism='[seq]')
real(wp), intent(in) :: x, y
real(wp), dimension(3), intent(in) :: length
logical :: is_inside
! Ellipse condition (x/a)^2 + (y/b)^2 <= 1
is_inside = (x/(0.5_wp*length(1)))**2 + (y/(0.5_wp*length(2)))**2 <= 1._wp
end function f_is_inside_ellipse
!> Compute a rotation matrix for converting to the rotating frame of the boundary
subroutine s_compute_rotation_matrix(angles, rotation_matrix, rotation_matrix_inverse)
$:GPU_ROUTINE(parallelism='[seq]')
real(wp), dimension(1:3), intent(in) :: angles
real(wp), dimension(1:3,1:3), intent(out) :: rotation_matrix
real(wp), dimension(1:3,1:3), intent(out) :: rotation_matrix_inverse
real(wp), dimension(3, 3, 3) :: rotation
! construct the x, y, and z rotation matrices
if (num_dims == 3) then
! also compute the x and y axes in 3D
rotation(1, 1,:) = [1._wp, 0._wp, 0._wp]
rotation(1, 2,:) = [0._wp, cos(angles(1)), -sin(angles(1))]
rotation(1, 3,:) = [0._wp, sin(angles(1)), cos(angles(1))]
rotation(2, 1,:) = [cos(angles(2)), 0._wp, sin(angles(2))]
rotation(2, 2,:) = [0._wp, 1._wp, 0._wp]
rotation(2, 3,:) = [-sin(angles(2)), 0._wp, cos(angles(2))]
! apply the y rotation to the x rotation
rotation_matrix(:,:) = matmul(rotation(1,:,:), rotation(2,:,:))
rotation_matrix_inverse(:,:) = matmul(transpose(rotation(2,:,:)), transpose(rotation(1,:,:)))
end if
! z component first, since it applies in 2D and 3D
rotation(3, 1,:) = [cos(angles(3)), -sin(angles(3)), 0._wp]
rotation(3, 2,:) = [sin(angles(3)), cos(angles(3)), 0._wp]
rotation(3, 3,:) = [0._wp, 0._wp, 1._wp]
if (num_dims == 3) then
! apply the z rotation to the xy rotation in 3D
rotation_matrix(:,:) = matmul(rotation_matrix(:,:), rotation(3,:,:))
rotation_matrix_inverse(:,:) = matmul(transpose(rotation(3,:,:)), rotation_matrix_inverse(:,:))
else
! write out only the z rotation in 2D
rotation_matrix(:,:) = rotation(3,:,:)
rotation_matrix_inverse(:,:) = transpose(rotation(3,:,:))
end if
end subroutine s_compute_rotation_matrix
end module m_patch_geometries