1 subroutine da_solve_poissoneqn_fct(grid, xbx, del2b, b)
3 !---------------------------------------------------------------------------
4 ! Purpose: Solve Del**2 B = A for B with zero gradient boundary conditions.
6 ! Method: 1) Compute spectral del2b using double forward FCT.
7 ! 2) Calculate spectral b.
8 ! 3) Reform gridpt. b using inverse double FCT.
9 ! 4) Remove mean b (arbitrary constant).
10 !--------------------------------------------------------------------------
14 type(domain), intent(inout) :: grid
15 type(xbx_type), intent(in) :: xbx ! Header & non-gridded vars.
16 real, intent(in) :: del2b(ims:ime,jms:jme,kms:kme) ! Del**2 B.
17 real, intent(out) :: b(ims:ime,jms:jme,kms:kme) ! B
19 integer :: vector_inc ! Increment between FST data.
20 integer :: vector_jump ! Jump between start of vectors.
21 integer :: vector_size ! Of form 2**p 3**q 5**r for FSTs.
22 integer :: num_vectors ! Number of FSTs to perform.
23 integer :: work_area ! Dimension for FST routine.
24 integer :: idim ! Size of 1st dimension for FST.
25 integer :: jdim ! Size of 2nd dimension for FST.
26 integer :: i, j, k, n, ij ! loop counter
27 real, allocatable :: work_1d(:) ! FFT work array
28 real :: global_mean(kts:kte)
29 real :: local_mean(kts:kte)
32 if (trace_use) call da_trace_entry("da_solve_poissoneqn_fct")
34 !---------------------------------------------------------------------------
36 !---------------------------------------------------------------------------
38 ! Calculate work space needed.
40 n = max(xbx%fft_ix*(grid%xp%jtex-grid%xp%jtsx+1), &
41 xbx%fft_jy*(grid%xp%itey-grid%xp%itsy+1+xbx%pad_num))
43 ! Allocate work arrays.
44 allocate(work_1d(1:n))
46 ! Copy del2b for transpose.
48 grid%xp%v1z(its:ite,jts:jte,kts:kte) = del2b(its:ite,jts:jte,kts:kte)
50 ! if (ite == ide) grid%xp%v1z(ite,jts:jte,kts:kte) = 0.0
51 ! if (jte == jde) grid%xp%v1z(its:ite,jte,kts:kte) = 0.0
53 !---------------------------------------------------------------------------
54 ! [2.0] Perform calculation of gridpoint b level by level:
55 !---------------------------------------------------------------------------
57 ! [2.1] Apply (i',j',k -> i,j',k') transpose (v1z -> v1x).
59 call da_transpose_z2x (grid)
61 ! [2.2] Set up FFT parameters:
64 jdim = grid%xp%jtex-grid%xp%jtsx+1
68 vector_size = idim - 1
72 work_area = (vector_size+1)*num_vectors
75 ! [2.3] Perform forward FFT:
77 do k = grid%xp%ktsx, grid%xp%ktex
79 do j=grid%xp%jtsx, grid%xp%jtex
82 work_1d(ij) = grid%xp%v1x(i,j,k)
90 call fft551(Forward_FFT, vector_inc, vector_jump, &
91 num_vectors, vector_size, &
92 xbx%fft_factors_x, xbx%trig_functs_x, &
93 work_1d(1), work_area)
96 do j=grid%xp%jtsx, grid%xp%jtex
99 grid%xp%v1x(i,j,k) = work_1d(ij)
102 do n=1, xbx%fft_pad_i
103 i=(n-1)*xbx%pad_inc + 1
105 grid%xp%v2x(i,j,k) = work_1d(ij)
110 !---------------------------------------------------------------------------
111 ! [3.0] For each k-level, perform forward FFT in y direction, apply spectral
112 ! Poisson equation, and then perform inverse FFT in y direction:
113 !---------------------------------------------------------------------------
115 ! [3.1] Apply (i,j',k' -> i',j,k') transpose (v1x -> v1y).
117 call da_transpose_x2y (grid)
118 call da_transpose_x2y_v2 (grid)
120 ! [3.2] Set up FFT parameters:
122 idim = grid%xp%itey - grid%xp%itsy + 1 + xbx%pad_num
127 vector_size = jdim - 1
130 work_area = (vector_size+1)*num_vectors
133 ! [2.3] Perform forward FFT in j:
135 do k = grid%xp%ktsy, grid%xp%ktey
138 do i=grid%xp%itsy, grid%xp%itey
140 work_1d(ij) = grid%xp%v1y(i,j,k)
146 work_1d(ij) = grid%xp%v2y(i,j,k)
150 do j=1, xbx%fft_pad_j
151 do i=grid%xp%itsy, grid%xp%itey+xbx%pad_num
157 call fft551(Forward_FFT, vector_inc, vector_jump, &
158 num_vectors, vector_size, &
159 xbx % fft_factors_y, xbx % trig_functs_y, &
160 work_1d(1), work_area)
162 !------------------------------------------------------------------------
163 ! [4.0] Solve spectral Poisson equation:
164 !------------------------------------------------------------------------
167 do j=grid%xp%jds, xbx%fft_jy
168 do i=grid%xp%itsy, grid%xp%itey
170 work_1d(ij) = xbx%fft_coeffs(i,j)*work_1d(ij)
175 work_1d(ij) = xbx%fft_coeffs(i,j)*work_1d(ij)
179 ! [2.3] Reform gridpt. b using inverse double FST in i.
181 call fft551(Inverse_FFT, vector_inc, vector_jump, &
182 num_vectors, vector_size, &
183 xbx % fft_factors_y, xbx % trig_functs_y, &
184 work_1d(1), work_area)
188 do i=grid%xp%itsy, grid%xp%itey
190 grid%xp%v1y(i,j,k) = work_1d(ij)
196 grid%xp%v2y(i,j,k) = work_1d(ij)
201 !---------------------------------------------------------------------------
202 ! Perform inverse FFT in x direction:
203 !---------------------------------------------------------------------------
205 ! Apply (i',j,k' -> i,j',k') transpose (v1y -> v1x).
207 call da_transpose_y2x (grid)
208 call da_transpose_y2x_v2 (grid)
210 ! Set up FFT parameters:
213 jdim = grid%xp%jtex-grid%xp%jtsx+1
217 vector_size = idim - 1
221 work_area = (vector_size+1)*num_vectors
223 do k = grid%xp%ktsx, grid%xp%ktex
225 do j=grid%xp%jtsx, grid%xp%jtex
228 work_1d(ij) = grid%xp%v1x(i,j,k)
231 do n=1, xbx%fft_pad_i
232 i=(n-1)*xbx%pad_inc + 1
234 work_1d(ij) = grid%xp%v2x(i,j,k)
238 call fft551(Inverse_FFT, vector_inc, vector_jump, &
239 num_vectors, vector_size, &
240 xbx % fft_factors_x, xbx % trig_functs_x, &
241 work_1d(1), work_area)
243 do j=grid%xp%jtsx, grid%xp%jtex
246 grid%xp%v1x(i,j,k) = work_1d(ij)
253 ! Apply (i,j',k') -> i',j',k) transpose to restore v1z.
255 call da_transpose_x2z (grid)
257 ! Remove mean b (set arbitrary constant to zero):
259 rij = 1.0/real((ide-ids+1)*(jde-jds+1))
262 local_mean(k) = sum(grid%xp%v1z(its:ite,jts:jte,k))*rij
265 call wrf_dm_sum_reals (local_mean, global_mean)
268 write (unit=stdout,fmt=*) 'TEST_COVERAGE_DA_Solve_PoissonEqn_FCT: global_mean(', &
269 k,') = ', global_mean(k)
272 ! [2.5] Write data array into b:
275 b(its:ite,jts:jte,k) = grid%xp%v1z(its:ite,jts:jte,k) - global_mean(k)
278 !---------------------------------------------------------------------------
280 !---------------------------------------------------------------------------
282 if (allocated(work_1d)) deallocate(work_1d)
284 if (trace_use) call da_trace_exit("da_solve_poissoneqn_fct")
286 end subroutine da_solve_poissoneqn_fct