1 subroutine da_solve_poissoneqn_fst(grid, xbx, del2b, b)
3 !--------------------------------------------------------------------------
4 ! Purpose: Solve Del**2 B = A for B with zero field boundary conditions.
6 ! Method: 1) Compute spectral del2b using double forward FST.
7 ! 2) Calculate spectral b.
8 ! 3) Reform gridpt. b using inverse double FST.
9 ! Note no mean removed (would make b.ne.0 at boundaries) so
10 ! arbitrary constant still present.
11 !--------------------------------------------------------------------------
15 type (domain), intent(inout) :: grid
16 type (xbx_type), intent(in) :: xbx ! Header & non-gridded vars.
17 real, intent(in) :: del2b(ims:ime,jms:jme,kms:kme) ! Del**2 B.
18 real, intent(out) :: b(ims:ime,jms:jme,kms:kme) ! B.
20 integer :: vector_inc ! Increment between FST data.
21 integer :: vector_jump ! Jump between start of vectors.
22 integer :: vector_size ! Of form 2**p 3**q 5**r for FSTs.
23 integer :: num_vectors ! Number of FSTs to perform.
24 integer :: work_area ! Dimension for FST routine.
25 integer :: idim ! Size of 1st dimension for FST.
26 integer :: jdim ! Size of 2nd dimension for FST.
28 integer :: i, j, k, n, ij ! loop counter
30 real, allocatable :: work_1d(:) ! FFT work array
32 if (trace_use) call da_trace_entry("da_solve_poissoneqn_fst")
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 forward FFT in x direction:
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
74 ! [2.3] Perform forward FFT:
76 do k = grid%xp%ktsx, grid%xp%ktex
78 do j=grid%xp%jtsx, grid%xp%jtex
81 work_1d(ij) = grid%xp%v1x(i,j,k)
90 call fft661(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)
95 do j=grid%xp%jtsx, grid%xp%jtex
98 grid%xp%v1x(i,j,k) = work_1d(ij)
101 do n=1, xbx%fft_pad_i
102 i=(n-1)*xbx%pad_inc + 1
104 grid%xp%v2x(i,j,k) = work_1d(ij)
109 !---------------------------------------------------------------------------
110 ! [3.0] For each k-level, perform forward FFT in y direction, apply spectral
111 ! Poisson equation, and then perform inverse FFT in y direction:
112 !---------------------------------------------------------------------------
114 ! [3.1] Apply (i,j',k' -> i',j,k') transpose (v1x -> v1y).
116 call da_transpose_x2y (grid)
117 call da_transpose_x2y_v2 (grid)
119 ! [3.2] Set up FFT parameters:
121 idim = grid%xp%itey - grid%xp%itsy + 1 + xbx%pad_num
126 vector_size = jdim - 1
129 work_area = (vector_size+1)*num_vectors
131 ! [2.3] Perform forward FFT in j:
133 do k = grid%xp%ktsy, grid%xp%ktey
136 do i=grid%xp%itsy, grid%xp%itey
138 work_1d(ij) = grid%xp%v1y(i,j,k)
144 work_1d(ij) = grid%xp%v2y(i,j,k)
148 do j=1, xbx%fft_pad_j
149 do i=grid%xp%itsy, grid%xp%itey+xbx%pad_num
155 call fft661(Forward_FFT, vector_inc, vector_jump, &
156 num_vectors, vector_size, &
157 xbx % fft_factors_y, xbx % trig_functs_y, &
158 work_1d(1), work_area)
160 !------------------------------------------------------------------------
161 ! [4.0] Solve spectral Poisson equation:
162 !------------------------------------------------------------------------
166 do i=grid%xp%itsy, grid%xp%itey
168 work_1d(ij) = xbx%fft_coeffs(i,j)*work_1d(ij)
173 work_1d(ij) = xbx%fft_coeffs(i,j)*work_1d(ij)
177 ! [2.3] Reform gridpt. b using inverse double FST in i.
179 call fft661(Inverse_FFT, vector_inc, vector_jump, &
180 num_vectors, vector_size, &
181 xbx % fft_factors_y, xbx % trig_functs_y, &
182 work_1d(1), work_area)
186 do i=grid%xp%itsy, grid%xp%itey
188 grid%xp%v1y(i,j,k) = work_1d(ij)
194 grid%xp%v2y(i,j,k) = work_1d(ij)
199 !---------------------------------------------------------------------------
200 ! Perform inverse FFT in x direction:
201 !---------------------------------------------------------------------------
203 ! Apply (i',j,k' -> i,j',k') transpose (v1y -> v1x).
205 call da_transpose_y2x (grid)
206 call da_transpose_y2x_v2 (grid)
208 ! Set up FFT parameters:
211 jdim = grid%xp%jtex-grid%xp%jtsx+1
215 vector_size = idim - 1
219 work_area = (vector_size+1)*num_vectors
221 do k = grid%xp%ktsx, grid%xp%ktex
223 do j=grid%xp%jtsx, grid%xp%jtex
224 do i=grid%xp%ids, grid%xp%ide
226 work_1d(ij) = grid%xp%v1x(i,j,k)
229 do n=1, xbx%fft_pad_i
230 i=(n-1)*xbx%pad_inc + 1
232 work_1d(ij) = grid%xp%v2x(i,j,k)
236 call fft661(Inverse_FFT, vector_inc, vector_jump, &
237 num_vectors, vector_size, &
238 xbx % fft_factors_x, xbx % trig_functs_x, &
239 work_1d(1), work_area)
241 do j=grid%xp%jtsx, grid%xp%jtex
244 grid%xp%v1x(i,j,k) = work_1d(ij)
251 ! Apply (i,j',k') -> i',j',k) transpose to restore v1z.
253 call da_transpose_x2z (grid)
255 !---------------------------------------------------------------------------
257 !---------------------------------------------------------------------------
259 if (allocated(work_1d)) deallocate(work_1d)
261 ! [2.5] Write data array into b:
263 b(its:ite,jts:jte,kts:kte) = grid%xp%v1z(its:ite,jts:jte,kts:kte)
265 if (trace_use) call da_trace_exit("da_solve_poissoneqn_fst")
267 end subroutine da_solve_poissoneqn_fst