MOM6
MOM_array_transform.F90
1 !> Module for supporting the rotation of a field's index map.
2 !! The implementation of each angle is described below.
3 !!
4 !! +90deg: B(i,j) = A(n-j,i)
5 !! = transpose, then row reverse
6 !! 180deg: B(i,j) = A(m-i,n-j)
7 !! = row reversal + column reversal
8 !! -90deg: B(i,j) = A(j,m-i)
9 !! = row reverse, then transpose
10 !!
11 !! 90 degree rotations change the shape of the field, and are handled
12 !! separately from 180 degree rotations.
13 
15 
16 implicit none
17 
18 private
19 public rotate_array
20 public rotate_array_pair
21 public rotate_vector
23 
24 
25 !> Rotate the elements of an array to the rotated set of indices.
26 !! Rotation is applied across the first and second axes of the array.
27 interface rotate_array
28  module procedure rotate_array_real_2d
29  module procedure rotate_array_real_3d
30  module procedure rotate_array_real_4d
31  module procedure rotate_array_integer
32  module procedure rotate_array_logical
33 end interface rotate_array
34 
35 
36 !> Rotate a pair of arrays which map to a rotated set of indices.
37 !! Rotation is applied across the first and second axes of the array.
38 !! This rotation should be applied when one field is mapped onto the other.
39 !! For example, a tracer indexed along u or v face points will map from one
40 !! to the other after a quarter turn, and back onto itself after a half turn.
42  module procedure rotate_array_pair_real_2d
43  module procedure rotate_array_pair_real_3d
44  module procedure rotate_array_pair_integer
45 end interface rotate_array_pair
46 
47 
48 !> Rotate an array pair representing the components of a vector.
49 !! Rotation is applied across the first and second axes of the array.
50 !! This rotation should be applied when the fields satisfy vector
51 !! transformation rules. For example, the u and v components of a velocity
52 !! will map from one to the other for quarter turns, with a sign change in one
53 !! component. A half turn will map elements onto themselves with sign changes
54 !! in both components.
55 interface rotate_vector
56  module procedure rotate_vector_real_2d
57  module procedure rotate_vector_real_3d
58  module procedure rotate_vector_real_4d
59 end interface rotate_vector
60 
61 
62 !> Allocate an array based on the rotated index map of an unrotated reference
63 !! array.
65  module procedure allocate_rotated_array_real_2d
66  module procedure allocate_rotated_array_real_3d
67  module procedure allocate_rotated_array_real_4d
68  module procedure allocate_rotated_array_integer
69 end interface allocate_rotated_array
70 
71 contains
72 
73 !> Rotate the elements of a 2d real array along first and second axes.
74 subroutine rotate_array_real_2d(A_in, turns, A)
75  real, intent(in) :: A_in(:,:) !< Unrotated array
76  integer, intent(in) :: turns !< Number of quarter turns
77  real, intent(out) :: A(:,:) !< Rotated array
78 
79  integer :: m, n
80 
81  m = size(a_in, 1)
82  n = size(a_in, 2)
83 
84  select case (modulo(turns, 4))
85  case(0)
86  a(:,:) = a_in(:,:)
87  case(1)
88  a(:,:) = transpose(a_in)
89  a(:,:) = a(n:1:-1, :)
90  case(2)
91  a(:,:) = a_in(m:1:-1, n:1:-1)
92  case(3)
93  a(:,:) = transpose(a_in(m:1:-1, :))
94  end select
95 end subroutine rotate_array_real_2d
96 
97 
98 !> Rotate the elements of a 3d real array along first and second axes.
99 subroutine rotate_array_real_3d(A_in, turns, A)
100  real, intent(in) :: A_in(:,:,:) !< Unrotated array
101  integer, intent(in) :: turns !< Number of quarter turns
102  real, intent(out) :: A(:,:,:) !< Rotated array
103 
104  integer :: k
105 
106  do k = 1, size(a_in, 3)
107  call rotate_array(a_in(:,:,k), turns, a(:,:,k))
108  enddo
109 end subroutine rotate_array_real_3d
110 
111 
112 !> Rotate the elements of a 4d real array along first and second axes.
113 subroutine rotate_array_real_4d(A_in, turns, A)
114  real, intent(in) :: A_in(:,:,:,:) !< Unrotated array
115  integer, intent(in) :: turns !< Number of quarter turns
116  real, intent(out) :: A(:,:,:,:) !< Rotated array
117 
118  integer :: n
119 
120  do n = 1, size(a_in, 4)
121  call rotate_array(a_in(:,:,:,n), turns, a(:,:,:,n))
122  enddo
123 end subroutine rotate_array_real_4d
124 
125 
126 !> Rotate the elements of a 2d integer array along first and second axes.
127 subroutine rotate_array_integer(A_in, turns, A)
128  integer, intent(in) :: A_in(:,:) !< Unrotated array
129  integer, intent(in) :: turns !< Number of quarter turns
130  integer, intent(out) :: A(:,:) !< Rotated array
131 
132  integer :: m, n
133 
134  m = size(a_in, 1)
135  n = size(a_in, 2)
136 
137  select case (modulo(turns, 4))
138  case(0)
139  a(:,:) = a_in(:,:)
140  case(1)
141  a(:,:) = transpose(a_in)
142  a(:,:) = a(n:1:-1, :)
143  case(2)
144  a(:,:) = a_in(m:1:-1, n:1:-1)
145  case(3)
146  a(:,:) = transpose(a_in(m:1:-1, :))
147  end select
148 end subroutine rotate_array_integer
149 
150 
151 !> Rotate the elements of a 2d logical array along first and second axes.
152 subroutine rotate_array_logical(A_in, turns, A)
153  logical, intent(in) :: A_in(:,:) !< Unrotated array
154  integer, intent(in) :: turns !< Number of quarter turns
155  logical, intent(out) :: A(:,:) !< Rotated array
156 
157  integer :: m, n
158 
159  m = size(a_in, 1)
160  n = size(a_in, 2)
161 
162  select case (modulo(turns, 4))
163  case(0)
164  a(:,:) = a_in(:,:)
165  case(1)
166  a(:,:) = transpose(a_in)
167  a(:,:) = a(n:1:-1, :)
168  case(2)
169  a(:,:) = a_in(m:1:-1, n:1:-1)
170  case(3)
171  a(:,:) = transpose(a_in(m:1:-1, :))
172  end select
173 end subroutine rotate_array_logical
174 
175 
176 !> Rotate the elements of a 2d real array pair along first and second axes.
177 subroutine rotate_array_pair_real_2d(A_in, B_in, turns, A, B)
178  real, intent(in) :: A_in(:,:) !< Unrotated scalar array pair
179  real, intent(in) :: B_in(:,:) !< Unrotated scalar array pair
180  integer, intent(in) :: turns !< Number of quarter turns
181  real, intent(out) :: A(:,:) !< Rotated scalar array pair
182  real, intent(out) :: B(:,:) !< Rotated scalar array pair
183 
184  if (modulo(turns, 2) /= 0) then
185  call rotate_array(b_in, turns, a)
186  call rotate_array(a_in, turns, b)
187  else
188  call rotate_array(a_in, turns, a)
189  call rotate_array(b_in, turns, b)
190  endif
191 end subroutine rotate_array_pair_real_2d
192 
193 
194 !> Rotate the elements of a 3d real array pair along first and second axes.
195 subroutine rotate_array_pair_real_3d(A_in, B_in, turns, A, B)
196  real, intent(in) :: A_in(:,:,:) !< Unrotated scalar array pair
197  real, intent(in) :: B_in(:,:,:) !< Unrotated scalar array pair
198  integer, intent(in) :: turns !< Number of quarter turns
199  real, intent(out) :: A(:,:,:) !< Rotated scalar array pair
200  real, intent(out) :: B(:,:,:) !< Rotated scalar array pair
201 
202  integer :: k
203 
204  do k = 1, size(a_in, 3)
205  call rotate_array_pair(a_in(:,:,k), b_in(:,:,k), turns, &
206  a(:,:,k), b(:,:,k))
207  enddo
208 end subroutine rotate_array_pair_real_3d
209 
210 
211 !> Rotate the elements of a 4d real array pair along first and second axes.
212 subroutine rotate_array_pair_integer(A_in, B_in, turns, A, B)
213  integer, intent(in) :: A_in(:,:) !< Unrotated scalar array pair
214  integer, intent(in) :: B_in(:,:) !< Unrotated scalar array pair
215  integer, intent(in) :: turns !< Number of quarter turns
216  integer, intent(out) :: A(:,:) !< Rotated scalar array pair
217  integer, intent(out) :: B(:,:) !< Rotated scalar array pair
218 
219  if (modulo(turns, 2) /= 0) then
220  call rotate_array(b_in, turns, a)
221  call rotate_array(a_in, turns, b)
222  else
223  call rotate_array(a_in, turns, a)
224  call rotate_array(b_in, turns, b)
225  endif
226 end subroutine rotate_array_pair_integer
227 
228 
229 !> Rotate the elements of a 2d real vector along first and second axes.
230 subroutine rotate_vector_real_2d(A_in, B_in, turns, A, B)
231  real, intent(in) :: A_in(:,:) !< First component of unrotated vector
232  real, intent(in) :: B_in(:,:) !< Second component of unrotated vector
233  integer, intent(in) :: turns !< Number of quarter turns
234  real, intent(out) :: A(:,:) !< First component of rotated vector
235  real, intent(out) :: B(:,:) !< Second component of unrotated vector
236 
237  call rotate_array_pair(a_in, b_in, turns, a, b)
238 
239  if (modulo(turns, 4) == 1 .or. modulo(turns, 4) == 2) &
240  a(:,:) = -a(:,:)
241 
242  if (modulo(turns, 4) == 2 .or. modulo(turns, 4) == 3) &
243  b(:,:) = -b(:,:)
244 end subroutine rotate_vector_real_2d
245 
246 
247 !> Rotate the elements of a 3d real vector along first and second axes.
248 subroutine rotate_vector_real_3d(A_in, B_in, turns, A, B)
249  real, intent(in) :: A_in(:,:,:) !< First component of unrotated vector
250  real, intent(in) :: B_in(:,:,:) !< Second component of unrotated vector
251  integer, intent(in) :: turns !< Number of quarter turns
252  real, intent(out) :: A(:,:,:) !< First component of rotated vector
253  real, intent(out) :: B(:,:,:) !< Second component of unrotated vector
254 
255  integer :: k
256 
257  do k = 1, size(a_in, 3)
258  call rotate_vector(a_in(:,:,k), b_in(:,:,k), turns, a(:,:,k), b(:,:,k))
259  enddo
260 end subroutine rotate_vector_real_3d
261 
262 
263 !> Rotate the elements of a 4d real vector along first and second axes.
264 subroutine rotate_vector_real_4d(A_in, B_in, turns, A, B)
265  real, intent(in) :: A_in(:,:,:,:) !< First component of unrotated vector
266  real, intent(in) :: B_in(:,:,:,:) !< Second component of unrotated vector
267  integer, intent(in) :: turns !< Number of quarter turns
268  real, intent(out) :: A(:,:,:,:) !< First component of rotated vector
269  real, intent(out) :: B(:,:,:,:) !< Second component of unrotated vector
270 
271  integer :: n
272 
273  do n = 1, size(a_in, 4)
274  call rotate_vector(a_in(:,:,:,n), b_in(:,:,:,n), turns, &
275  a(:,:,:,n), b(:,:,:,n))
276  enddo
277 end subroutine rotate_vector_real_4d
278 
279 
280 !> Allocate a 2d real array on the rotated index map of a reference array.
281 subroutine allocate_rotated_array_real_2d(A_in, lb, turns, A)
282  ! NOTE: lb must be declared before A_in
283  integer, intent(in) :: lb(2) !< Lower index bounds of A_in
284  real, intent(in) :: A_in(lb(1):, lb(2):) !< Reference array
285  integer, intent(in) :: turns !< Number of quarter turns
286  real, allocatable, intent(inout) :: A(:,:) !< Array on rotated index
287 
288  integer :: ub(2)
289 
290  ub(:) = ubound(a_in)
291 
292  if (modulo(turns, 2) /= 0) then
293  allocate(a(lb(2):ub(2), lb(1):ub(1)))
294  else
295  allocate(a(lb(1):ub(1), lb(2):ub(2)))
296  endif
297 end subroutine allocate_rotated_array_real_2d
298 
299 
300 !> Allocate a 3d real array on the rotated index map of a reference array.
301 subroutine allocate_rotated_array_real_3d(A_in, lb, turns, A)
302  ! NOTE: lb must be declared before A_in
303  integer, intent(in) :: lb(3) !< Lower index bounds of A_in
304  real, intent(in) :: A_in(lb(1):, lb(2):, lb(3):) !< Reference array
305  integer, intent(in) :: turns !< Number of quarter turns
306  real, allocatable, intent(inout) :: A(:,:,:) !< Array on rotated index
307 
308  integer :: ub(3)
309 
310  ub(:) = ubound(a_in)
311 
312  if (modulo(turns, 2) /= 0) then
313  allocate(a(lb(2):ub(2), lb(1):ub(1), lb(3):ub(3)))
314  else
315  allocate(a(lb(1):ub(1), lb(2):ub(2), lb(3):ub(3)))
316  endif
317 end subroutine allocate_rotated_array_real_3d
318 
319 
320 !> Allocate a 4d real array on the rotated index map of a reference array.
321 subroutine allocate_rotated_array_real_4d(A_in, lb, turns, A)
322  ! NOTE: lb must be declared before A_in
323  integer, intent(in) :: lb(4) !< Lower index bounds of A_in
324  real, intent(in) :: A_in(lb(1):,lb(2):,lb(3):,lb(4):) !< Reference array
325  integer, intent(in) :: turns !< Number of quarter turns
326  real, allocatable, intent(inout) :: A(:,:,:,:) !< Array on rotated index
327 
328  integer:: ub(4)
329 
330  ub(:) = ubound(a_in)
331 
332  if (modulo(turns, 2) /= 0) then
333  allocate(a(lb(2):ub(2), lb(1):ub(1), lb(3):ub(3), lb(4):ub(4)))
334  else
335  allocate(a(lb(1):ub(1), lb(2):ub(2), lb(3):ub(3), lb(4):ub(4)))
336  endif
337 end subroutine allocate_rotated_array_real_4d
338 
339 
340 !> Allocate a 2d integer array on the rotated index map of a reference array.
341 subroutine allocate_rotated_array_integer(A_in, lb, turns, A)
342  integer, intent(in) :: lb(2) !< Lower index bounds of A_in
343  integer, intent(in) :: A_in(lb(1):,lb(2):) !< Reference array
344  integer, intent(in) :: turns !< Number of quarter turns
345  integer, allocatable, intent(inout) :: A(:,:) !< Array on rotated index
346 
347  integer :: ub(2)
348 
349  ub(:) = ubound(a_in)
350 
351  if (modulo(turns, 2) /= 0) then
352  allocate(a(lb(2):ub(2), lb(1):ub(1)))
353  else
354  allocate(a(lb(1):ub(1), lb(2):ub(2)))
355  endif
356 end subroutine allocate_rotated_array_integer
357 
358 end module mom_array_transform
Rotate an array pair representing the components of a vector. Rotation is applied across the first an...
Module for supporting the rotation of a field&#39;s index map. The implementation of each angle is descri...
Rotate the elements of an array to the rotated set of indices. Rotation is applied across the first a...
Allocate an array based on the rotated index map of an unrotated reference array. ...
Rotate a pair of arrays which map to a rotated set of indices. Rotation is applied across the first a...