MONC
iterativesolver.F90
Go to the documentation of this file.
1 
4  use collections_mod, only : map_type
7  use state_mod, only : model_state_type
17  use mpi, only : mpi_max, mpi_sum, mpi_comm_world, mpi_request_null, mpi_statuses_ignore
18  implicit none
19 
20 #ifndef TEST_MODE
21  private
22 #endif
23 
26  real(kind=DEFAULT_PRECISION) :: n, s, e, w
27  real(kind=DEFAULT_PRECISION), dimension(:), allocatable :: u, d, p, lu_d, lu_u, vol
28  end type matrix_type
29 
30  real(kind=DEFAULT_PRECISION) :: tolerance, relaxation
31  integer :: max_iterations, & !< Maximum number of BiCGStab iterations
33  logical :: symm_prob
34 
35  real(kind=DEFAULT_PRECISION), parameter :: tiny = 1.0e-16
36 
38  real(kind=DEFAULT_PRECISION), dimension(:,:,:), allocatable :: psource, prev_p
39  logical :: first_run=.true.
40  type(matrix_type) :: a
41 
43 contains
44 
48  iterativesolver_get_descriptor%name="iterativesolver"
54 
57  subroutine initialisation_callback(current_state)
58  type(model_state_type), target, intent(inout) :: current_state
59 
60  if (.not. is_component_enabled(current_state%options_database, "diverr")) then
61  call log_master_log(log_error, "The iterative solver component requires the diverr component to be enabled")
62  end if
63 
64  tolerance=options_get_real(current_state%options_database, "tolerance")
65  max_iterations=options_get_integer(current_state%options_database, "max_iterations")
66  preconditioner_iterations=options_get_integer(current_state%options_database, "preconditioner_iterations")
67  symm_prob=options_get_logical(current_state%options_database, "symm_prob")
68 
69  call init_halo_communication(current_state, get_single_field_per_halo_cell, halo_swap_state, 1, .false.)
70 
71  allocate(psource(current_state%local_grid%size(z_index) + current_state%local_grid%halo_size(z_index) * 2, &
72  current_state%local_grid%size(y_index) + current_state%local_grid%halo_size(y_index) * 2, &
73  current_state%local_grid%size(x_index) + current_state%local_grid%halo_size(x_index) * 2),&
74  prev_p(current_state%local_grid%size(z_index) + current_state%local_grid%halo_size(z_index) * 2, &
75  current_state%local_grid%size(y_index) + current_state%local_grid%halo_size(y_index) * 2, &
76  current_state%local_grid%size(x_index) + current_state%local_grid%halo_size(x_index) * 2))
77 
78  a=create_problem_matrix(current_state%local_grid%size(z_index))
79  call set_matrix_for_poisson(current_state%global_grid%configuration, a, current_state%local_grid%size(z_index))
80  end subroutine initialisation_callback
81 
84  subroutine timestep_callback(current_state)
85  type(model_state_type), target, intent(inout) :: current_state
86 
87  integer :: i_strt, i_end, j_strt, j_end, k_end
88 
89  i_strt = current_state%local_grid%local_domain_start_index(x_index)
90  i_end = current_state%local_grid%local_domain_end_index(x_index)
91  j_strt = current_state%local_grid%local_domain_start_index(y_index)
92  j_end = current_state%local_grid%local_domain_end_index(y_index)
93  k_end = current_state%local_grid%size(z_index)
94 
95  call complete_psrce_calculation(current_state, current_state%local_grid%halo_size(y_index), &
96  current_state%local_grid%halo_size(x_index))
97 
98  call initiate_nonblocking_halo_swap(current_state, halo_swap_state, copy_p_to_halo_buffer)
99  call deduce_global_divmax(current_state)
100  call complete_nonblocking_halo_swap(current_state, halo_swap_state, perform_local_data_copy_for_p, copy_halo_buffer_to_p)
101 
102  psource=current_state%p%data
103  if (first_run) then
104  ! If first timestep then initial guess is zero
105  current_state%p%data=0.0_default_precision
106  first_run=.false.
107  else
108  ! Initial guess is set to previous timesteps p
109  current_state%p%data=prev_p
110  end if
111 
112  if (symm_prob) then
113  call cg_solver(current_state, a, current_state%p%data, psource, i_strt, i_end, j_strt, j_end, k_end)
114  else
115  call bicgstab(current_state, a, current_state%p%data, psource, i_strt, i_end, j_strt, j_end, k_end)
116  end if
117 
118  prev_p=current_state%p%data
119  end subroutine timestep_callback
120 
123  subroutine finalisation_callback(current_state)
124  type(model_state_type), target, intent(inout) :: current_state
125 
126  call finalise_halo_communication(halo_swap_state)
127  deallocate(psource, prev_p, a%u, a%d, a%p, a%lu_u, a%lu_d, a%vol)
128  end subroutine finalisation_callback
129 
135  subroutine bicgstab(current_state, A, x, b, i_strt, i_end, j_strt, j_end, k_end)
136  type(model_state_type), target, intent(inout) :: current_state
137  type(matrix_type), intent(inout) :: A
138  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(inout) :: x
139  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(in) :: b
140  integer, intent(in) :: i_strt, i_end, j_strt, j_end, k_end
141 
142  integer :: it, i, j, k
143  real(kind=DEFAULT_PRECISION) :: sc_err, alf, omg, nrm, my_rho, bet, tt, ts, ss, err, init_err, inner_prod_results(3)
144  real(kind=DEFAULT_PRECISION), dimension(current_state%local_grid%size(Z_INDEX) + & current_state%local_grid%halo_size(Z_INDEX) * 2, & current_state%local_grid%size(Y_INDEX) + current_state%local_grid%halo_size(Y_INDEX) * 2, & current_state%local_grid%size(X_INDEX) + current_state%local_grid%halo_size(X_INDEX) * 2) :: Ax, r, cr, pp, v, t, s, cs
145 
146  ! Calculate scale factor for error
147  sc_err = sqrt(inner_prod(current_state, b, b, i_strt, i_end, j_strt, j_end, k_end))
148  sc_err = max(sc_err, 0.0001_default_precision)
149 
150  ! Calculate initial residual
151  call calc_ax(current_state, a, x, ax)
152 
153  do i = i_strt, i_end
154  do j = j_strt, j_end
155  do k = 2, k_end
156  r(k,j,i) = b(k,j,i) - ax(k,j,i)
157  cr(k,j,i) = r(k,j,i)
158  end do
159  end do
160  end do
161 
162  my_rho = inner_prod(current_state, r, r, i_strt, i_end, j_strt, j_end, k_end)
163  err = sqrt(my_rho)/sc_err
164  init_err = err
165 
166  alf = 1.0_default_precision
167  omg = 1.0_default_precision
168  nrm = 1.0_default_precision
169 
170  if (err .ge. tolerance) then
171  do it=1, max_iterations
172  if (it > 1) my_rho = inner_prod(current_state, r, cr, i_strt, i_end, j_strt, j_end, k_end)
173  bet = (my_rho/nrm) * (alf/omg)
174  if (it == 1) then
175  call precond(current_state, a, pp, r, preconditioner_iterations)
176  else
177  do i = i_strt, i_end
178  do j = j_strt, j_end
179  do k = 2, k_end
180  t(k,j,i) = r(k,j,i) - bet*omg*v(k,j,i)
181  end do
182  end do
183  end do
184  call precond(current_state, a, s, t, preconditioner_iterations)
185  do i = i_strt, i_end
186  do j = j_strt, j_end
187  do k = 2, k_end
188  pp(k,j,i) = s(k,j,i) + bet*pp(k,j,i)
189  end do
190  end do
191  end do
192  end if
193  call calc_ax(current_state, a, pp, v)
194  nrm = inner_prod(current_state, cr, v, i_strt, i_end, j_strt, j_end, k_end)
195  alf = my_rho / nrm
196 
197  do i = i_strt, i_end
198  do j = j_strt, j_end
199  do k = 2, k_end
200  s(k,j,i) = r(k,j,i) - alf*v(k,j,i)
201  end do
202  end do
203  end do
204 
205  call precond(current_state, a, cs, s, preconditioner_iterations)
206  call calc_ax(current_state, a, cs, t)
207 
208  inner_prod_results=inner_prod_three_way(current_state, t, s, i_strt, i_end, j_strt, j_end, k_end)
209  tt = inner_prod_results(1)
210  ts = inner_prod_results(2)
211  ss = inner_prod_results(3)
212  omg = ts/tt
213  x = x + alf*pp + omg*cs
214  do i = i_strt, i_end
215  do j = j_strt, j_end
216  do k = 2, k_end
217  r(k,j,i) = s(k,j,i) - omg*t(k,j,i)
218  end do
219  end do
220  end do
221  nrm = my_rho
222 
223  if (abs(omg) < tiny) then
224  call log_log(log_warn, "Convergence problem, omega="//conv_to_string(omg))
225  endif
226 
227  err = sqrt(ss - 2*omg*ts + omg**2 *tt)/sc_err
228  if (err < tolerance) exit
229  end do
230  end if
231 
232  if (err > tolerance) then
233  call log_log(log_warn, "Convergence failed, RNorm="//conv_to_string(err, exponent=.true.))
234  else if (current_state%parallel%my_rank==0 .and. log_get_logging_level() .eq. log_debug) then
235  call log_log(log_debug, "Converged in "//trim(conv_to_string(it))//" iterations with RNorm="//&
236  trim(conv_to_string(err, 5, .true.))//" initial norm="//trim(conv_to_string(init_err, 5, .true.)))
237  end if
238  end subroutine bicgstab
239 
245  subroutine cg_solver(current_state, A, x, b, i_strt, i_end, j_strt, j_end, k_end)
246  type(model_state_type), target, intent(inout) :: current_state
247  type(matrix_type), intent(inout) :: A
248  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(inout) :: x
249  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(in) :: b
250  integer, intent(in) :: i_strt, i_end, j_strt, j_end, k_end
251 
252  integer :: it, k, i, j
253  real(kind=DEFAULT_PRECISION) :: sc_err, alf, bet, err, init_err, rho
254  real(kind=DEFAULT_PRECISION), dimension(current_state%local_grid%size(Z_INDEX) + & current_state%local_grid%halo_size(Z_INDEX) * 2, & current_state%local_grid%size(Y_INDEX) + current_state%local_grid%halo_size(Y_INDEX) * 2, & current_state%local_grid%size(X_INDEX) + current_state%local_grid%halo_size(X_INDEX) * 2) :: Ax, r, z, p
255 
256  ! first rescale RHS for symmetry (this could be done when p_source is calculated
257  do i=current_state%local_grid%local_domain_start_index(x_index), current_state%local_grid%local_domain_end_index(x_index)
258  do j=current_state%local_grid%local_domain_start_index(y_index), current_state%local_grid%local_domain_end_index(y_index)
259 
260  r(1,j,i) = 0.0_default_precision
261  do k=2,current_state%local_grid%size(z_index)
262  r(k,j,i) = b(k,j,i) * a%vol(k)
263  end do
264  end do
265  end do
266 
267  ! Calculate scale factor for error
268 
269  call calc_ax(current_state, a, x, ax)
270 
271  sc_err = sqrt(inner_prod(current_state, r, r, i_strt, i_end, j_strt, j_end, k_end))
272  sc_err = max(sc_err, 0.0001_default_precision)
273  r = r - ax
274  init_err = sqrt(inner_prod(current_state, r, r, i_strt, i_end, j_strt, j_end, k_end))/sc_err
275 
276  do it=1, max_iterations
277  if( it == 1 ) then
278  call precond(current_state, a, p, r, preconditioner_iterations)
279  rho = inner_prod(current_state, p, r, i_strt, i_end, j_strt, j_end, k_end)
280  alf = rho
281  else
282  call precond(current_state, a, z, r, preconditioner_iterations)
283  alf = inner_prod(current_state, z, r, i_strt, i_end, j_strt, j_end, k_end)
284  bet = alf/rho
285  rho = alf
286  p = z + bet*p
287  end if
288 
289  call calc_ax(current_state, a, p, ax)
290  alf = alf/inner_prod(current_state, p, ax, i_strt, i_end, j_strt, j_end, k_end)
291  x = x + alf*p
292  r = r - alf*ax
293 
294  err = sqrt(inner_prod(current_state, r, r, i_strt, i_end, j_strt, j_end, k_end))/sc_err
295  if (err < tolerance) exit
296  end do
297 
298  if( current_state%parallel%my_rank == 0 ) print*,it, err, init_err
299 
300  if (err > tolerance) then
301  call log_log(log_warn, "Convergence failed, RNorm="//conv_to_string(err, exponent=.true.))
302  else if (current_state%parallel%my_rank==0 .and. log_get_logging_level() .eq. log_debug) then
303  call log_log(log_debug, "Converged in "//trim(conv_to_string(it))//" iterations with RNorm="//&
304  trim(conv_to_string(err, 5, .true.))//" initial norm="//trim(conv_to_string(init_err, 5, .true.)))
305  end if
306  end subroutine cg_solver
307 
314  subroutine precond(current_state, A, s, r, preits)
315  type(model_state_type), target, intent(inout) :: current_state
316  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(in) :: r
317  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(inout) :: s
318  integer, intent(in) :: preits
319  type(matrix_type), intent(inout) :: A
320 
321  real(kind=DEFAULT_PRECISION), dimension(current_state%local_grid%size(Z_INDEX) + & current_state%local_grid%halo_size(Z_INDEX) * 2, current_state%local_grid%size(Y_INDEX) + & current_state%local_grid%halo_size(Y_INDEX) * 2, current_state%local_grid%size(X_INDEX) + & current_state%local_grid%halo_size(X_INDEX) * 2) :: t
322  real(kind=DEFAULT_PRECISION), dimension(current_state%local_grid%size(Z_INDEX)) :: s_k
323  integer :: it, i, j, k
324 
325  if (preits .lt. 0) then
326  s=r
327  return
328  end if
329 
330  do i=current_state%local_grid%local_domain_start_index(x_index), current_state%local_grid%local_domain_end_index(x_index)
331  do j=current_state%local_grid%local_domain_start_index(y_index), current_state%local_grid%local_domain_end_index(y_index)
332  s(1,j,i) = 0.0_default_precision
333  k=2
334  s(k,j,i)=r(k,j,i)*a%LU_d(k)
335  do k=3,current_state%local_grid%size(z_index)
336  s(k,j,i)=(r(k,j,i) - a%d(k)*s(k-1,j,i))*a%lu_d(k)
337  end do
338  do k=current_state%local_grid%size(z_index)-1, 2, -1
339  s(k,j,i)=s(k,j,i) - a%lu_u(k)*s(k+1,j,i)
340  end do
341  end do
342  end do
343 
344  do it=1, preits
345  call calc_ax(current_state, a, s, t)
346  do i=current_state%local_grid%local_domain_start_index(x_index), current_state%local_grid%local_domain_end_index(x_index)
347  do j=current_state%local_grid%local_domain_start_index(y_index), current_state%local_grid%local_domain_end_index(y_index)
348  k=2
349  s_k(k)=(r(k,j,i) - t(k,j,i))*a%lu_d(k)
350  do k=3,current_state%local_grid%size(z_index)
351  s_k(k)=(r(k,j,i) - t(k,j,i) - a%d(k)*s_k(k-1))*a%lu_d(k)
352  end do
353  k=current_state%local_grid%size(z_index)
354  s(k,j,i)=s(k,j,i)+s_k(k)
355  do k=current_state%local_grid%size(z_index)-1, 2, -1
356  s_k(k)=s_k(k) - a%lu_u(k)*s_k(k+1)
357  s(k,j,i)=s(k,j,i) + relaxation*s_k(k)
358  end do
359  end do
360  end do
361  end do
362  end subroutine precond
363 
369  subroutine calc_ax(current_state, A, x, Ax)
370  type(model_state_type), target, intent(inout) :: current_state
371  type(matrix_type), intent(in) :: A
372  real(kind=DEFAULT_PRECISION), dimension(:,:,:), target, intent(inout) :: x, Ax
373 
374  integer :: i, k, j, n, istart, iend, jstart, jend
375  type(field_data_wrapper_type) :: source_data
376 
377  source_data%data=>x
378 
379  call initiate_nonblocking_halo_swap(current_state, halo_swap_state, &
380  copy_calc_ax_to_halo_buffer, source_data=(/source_data/))
381 
382  ax(1,:,:) = 0.0_default_precision
383  if (symm_prob) then
384  do n=1, 5
385  if (n==1) then
386  istart=current_state%local_grid%local_domain_start_index(x_index)+1
387  iend=current_state%local_grid%local_domain_end_index(x_index)-1
388  jstart=current_state%local_grid%local_domain_start_index(y_index)+1
389  jend=current_state%local_grid%local_domain_end_index(y_index)-1
390  else if (n==2) then
391  istart=current_state%local_grid%local_domain_start_index(x_index)
392  iend=current_state%local_grid%local_domain_start_index(x_index)
393  else if (n==3) then
394  istart=current_state%local_grid%local_domain_end_index(x_index)
395  iend=current_state%local_grid%local_domain_end_index(x_index)
396  else if (n==4) then
397  jstart=current_state%local_grid%local_domain_start_index(y_index)
398  jend=current_state%local_grid%local_domain_start_index(y_index)
399  istart=current_state%local_grid%local_domain_start_index(x_index)
400  iend=current_state%local_grid%local_domain_end_index(x_index)
401  else if (n==5) then
402  jstart=current_state%local_grid%local_domain_end_index(y_index)
403  jend=current_state%local_grid%local_domain_end_index(y_index)
404  end if
405  do i=istart, iend
406  do j=jstart, jend
407  k=2
408  ax(k,j,i)=a%vol(k)*(a%n*(x(k,j,i+1)+x(k,j,i-1))+a%e*(x(k,j+1,i)+x(k,j-1,i)))+ a%u(k)*x(k+1,j,i)+a%p(k)*x(k,j,i)
409  do k=3,current_state%local_grid%size(z_index)-1
410  ax(k,j,i)=a%vol(k)*(a%n*(x(k,j,i+1)+x(k,j,i-1))+a%e*(x(k,j+1,i)+x(k,j-1,i)))+&
411  a%u(k)*x(k+1,j,i)+a%d(k)*x(k-1,j,i)+a%p(k)*x(k,j,i)
412  end do
413  k=current_state%local_grid%size(z_index)
414  ax(k,j,i) = a%vol(k)*(a%n*(x(k,j,i+1)+x(k,j,i-1))+a%e*(x(k,j+1,i)+x(k,j-1,i)))+ a%d(k)*x(k-1,j,i)+a%p(k)*x(k,j,i)
415  end do
416  end do
417  if (n==1) then
418  call complete_nonblocking_halo_swap(current_state, halo_swap_state, perform_local_data_copy_for_calc_ax, &
419  copy_halo_buffer_to_calc_ax, source_data=(/source_data/))
420  end if
421  end do
422  else
423  do n=1, 5
424  if (n==1) then
425  istart=current_state%local_grid%local_domain_start_index(x_index)+1
426  iend=current_state%local_grid%local_domain_end_index(x_index)-1
427  jstart=current_state%local_grid%local_domain_start_index(y_index)+1
428  jend=current_state%local_grid%local_domain_end_index(y_index)-1
429  else if (n==2) then
430  istart=current_state%local_grid%local_domain_start_index(x_index)
431  iend=current_state%local_grid%local_domain_start_index(x_index)
432  else if (n==3) then
433  istart=current_state%local_grid%local_domain_end_index(x_index)
434  iend=current_state%local_grid%local_domain_end_index(x_index)
435  else if (n==4) then
436  jstart=current_state%local_grid%local_domain_start_index(y_index)
437  jend=current_state%local_grid%local_domain_start_index(y_index)
438  istart=current_state%local_grid%local_domain_start_index(x_index)
439  iend=current_state%local_grid%local_domain_end_index(x_index)
440  else if (n==5) then
441  jstart=current_state%local_grid%local_domain_end_index(y_index)
442  jend=current_state%local_grid%local_domain_end_index(y_index)
443  end if
444  do i=istart, iend
445  do j=jstart, jend
446  k=2
447  ax(k,j,i)=a%n*(x(k,j,i+1)+x(k,j,i-1))+a%e*(x(k,j+1,i)+x(k,j-1,i))+ a%u(k)*x(k+1,j,i)+a%p(k)*x(k,j,i)
448  do k=3,current_state%local_grid%size(z_index)-1
449  ax(k,j,i)=a%n*(x(k,j,i+1)+x(k,j,i-1))+a%e*(x(k,j+1,i)+x(k,j-1,i))+&
450  a%u(k)*x(k+1,j,i)+a%d(k)*x(k-1,j,i)+a%p(k)*x(k,j,i)
451  end do
452  k=current_state%local_grid%size(z_index)
453  ax(k,j,i) = a%n*(x(k,j,i+1)+x(k,j,i-1))+a%e*(x(k,j+1,i)+x(k,j-1,i))+ a%d(k)*x(k-1,j,i)+a%p(k)*x(k,j,i)
454  end do
455  end do
456  if (n==1) then
457  call complete_nonblocking_halo_swap(current_state, halo_swap_state, perform_local_data_copy_for_calc_ax, &
458  copy_halo_buffer_to_calc_ax, source_data=(/source_data/))
459  end if
460  end do
461  endif
462  end subroutine calc_ax
463 
469  real(kind=DEFAULT_PRECISION) function inner_prod(current_state, x, y, i_strt, i_end, j_strt, j_end, k_end)
470  type(model_state_type), target, intent(inout) :: current_state
471  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(in) :: x, y
472  integer, intent(in) :: i_strt, i_end, j_strt, j_end, k_end
473 
474  real(kind=DEFAULT_PRECISION) :: local_sum, global_sum
475  integer :: ierr, i, j, k
476 
477  local_sum=0.0_default_precision
478 
479  do i=i_strt, i_end
480  do j=j_strt, j_end
481  do k=2, k_end
482  local_sum=local_sum+x(k,j,i)*y(k,j,i)
483  end do
484  end do
485  end do
486 
487  call mpi_allreduce(local_sum, global_sum, 1, precision_type, mpi_sum, current_state%parallel%monc_communicator, ierr)
488  inner_prod=global_sum
489  end function inner_prod
490 
497  function inner_prod_three_way(current_state, t, s, i_strt, i_end, j_strt, j_end, k_end)
498  type(model_state_type), target, intent(inout) :: current_state
499  integer, intent(in) :: i_strt, i_end, j_strt, j_end, k_end
500  real(kind=DEFAULT_PRECISION), dimension(:,:,:), intent(in) :: t, s
501  real(kind=DEFAULT_PRECISION), dimension(3) :: inner_prod_three_way
502 
503  real(kind=DEFAULT_PRECISION), dimension(3) :: local_sum, global_sum
504  integer :: ierr, i, j, k
505 
506  local_sum(1)=0.0_default_precision
507  local_sum(2)=0.0_default_precision
508  local_sum(3)=0.0_default_precision
509 
510  do i=i_strt, i_end
511  do j=j_strt, j_end
512  do k=2, k_end
513  local_sum(1)=local_sum(1)+t(k,j,i)*t(k,j,i)
514  local_sum(2)=local_sum(2)+t(k,j,i)*s(k,j,i)
515  local_sum(3)=local_sum(3)+s(k,j,i)*s(k,j,i)
516  end do
517  end do
518  end do
519 
520  call mpi_allreduce(local_sum, global_sum, 3, precision_type, mpi_sum, current_state%parallel%monc_communicator, ierr)
521  inner_prod_three_way=global_sum
522  end function inner_prod_three_way
523 
528  subroutine set_matrix_for_poisson(grid_configuration, A, z_size)
529  type(grid_configuration_type), intent(inout) :: grid_configuration
530  type(matrix_type), intent(inout) :: A
531  integer, intent(in) :: z_size
532 
533  integer :: k
534  real(kind=DEFAULT_PRECISION) :: d_sc, concat_scalars
535 
536  a%n=grid_configuration%horizontal%cx*grid_configuration%horizontal%cx
537  a%s=a%n
538  a%e=grid_configuration%horizontal%cy*grid_configuration%horizontal%cy
539  a%w=a%e
540  concat_scalars=a%n+a%s+a%e+a%w
541  do k=2, z_size
542  if (symm_prob) then
543  a%vol(k)=grid_configuration%vertical%dz(k)
544  d_sc=1.0/grid_configuration%vertical%rhon(k)
545  else
546  d_sc=grid_configuration%vertical%rdz(k) / grid_configuration%vertical%rhon(k)
547  a%vol(k)=1.0
548  endif
549 
550  if (k==z_size) then
551  a%u(k)=0.0_default_precision
552  else
553  a%u(k)=grid_configuration%vertical%rho(k)*grid_configuration%vertical%rdzn(k+1)
554  end if
555  if (k==2) then
556  a%d(k)=0.0_default_precision
557  else
558  a%d(k)=grid_configuration%vertical%rho(k-1)*grid_configuration%vertical%rdzn(k)
559  end if
560  a%p(k) = d_sc * (-(a%u(k) + a%d(k))) - concat_scalars * a%vol(k)
561  a%u(k)=d_sc * a%u(k)
562  a%d(k)=d_sc * a%d(k)
563  end do
564  k=2
565  a%lu_d(k)=1.0_default_precision/a%p(k)
566  a%lu_u(k)=a%lu_d(k)*a%u(k)
567  do k=3, z_size
568  a%lu_d(k)=1.0_default_precision/(a%p(k) - a%d(k)*a%lu_u(k-1))
569  a%lu_u(k)=a%u(k)*a%lu_d(k)
570  end do
571  end subroutine set_matrix_for_poisson
572 
575  subroutine deduce_global_divmax(current_state)
576  type(model_state_type), target, intent(inout) :: current_state
577 
578  integer :: ierr
579 
580  call mpi_allreduce(current_state%local_divmax, current_state%global_divmax, 1, precision_type, mpi_max, &
581  current_state%parallel%monc_communicator, ierr)
582  end subroutine deduce_global_divmax
583 
592  subroutine copy_p_to_halo_buffer(current_state, neighbour_description, dim, source_index, &
593  pid_location, current_page, source_data)
594  type(model_state_type), intent(inout) :: current_state
595  integer, intent(in) :: dim, pid_location, source_index
596  integer, intent(inout) :: current_page(:)
597  type(neighbour_description_type), intent(inout) :: neighbour_description
598  type(field_data_wrapper_type), dimension(:), intent(in), optional :: source_data
599 
600  call copy_field_to_buffer(current_state%local_grid, neighbour_description%send_halo_buffer, current_state%p%data, &
601  dim, source_index, current_page(pid_location))
602 
603  current_page(pid_location)=current_page(pid_location)+1
604  end subroutine copy_p_to_halo_buffer
605 
614  subroutine copy_calc_ax_to_halo_buffer(current_state, neighbour_description, dim, source_index, &
615  pid_location, current_page, source_data)
616  type(model_state_type), intent(inout) :: current_state
617  integer, intent(in) :: dim, pid_location, source_index
618  integer, intent(inout) :: current_page(:)
619  type(neighbour_description_type), intent(inout) :: neighbour_description
620  type(field_data_wrapper_type), dimension(:), intent(in), optional :: source_data
621 
622  type(field_data_wrapper_type) :: selected_source
623 
624  selected_source=source_data(1)
626  call copy_field_to_buffer(current_state%local_grid, neighbour_description%send_halo_buffer, selected_source%data, &
627  dim, source_index, current_page(pid_location))
628 
629  current_page(pid_location)=current_page(pid_location)+1
630  end subroutine copy_calc_ax_to_halo_buffer
631 
640  subroutine copy_halo_buffer_to_p(current_state, neighbour_description, dim, target_index, &
641  neighbour_location, current_page, source_data)
642  type(model_state_type), intent(inout) :: current_state
643  integer, intent(in) :: dim, target_index, neighbour_location
644  integer, intent(inout) :: current_page(:)
645  type(neighbour_description_type), intent(inout) :: neighbour_description
646  type(field_data_wrapper_type), dimension(:), intent(in), optional :: source_data
647 
648  call copy_buffer_to_field(current_state%local_grid, neighbour_description%recv_halo_buffer, current_state%p%data, &
649  dim, target_index, current_page(neighbour_location))
650 
651  current_page(neighbour_location)=current_page(neighbour_location)+1
652  end subroutine copy_halo_buffer_to_p
653 
662  subroutine copy_halo_buffer_to_calc_ax(current_state, neighbour_description, dim, target_index, &
663  neighbour_location, current_page, source_data)
664  type(model_state_type), intent(inout) :: current_state
665  integer, intent(in) :: dim, target_index, neighbour_location
666  integer, intent(inout) :: current_page(:)
667  type(neighbour_description_type), intent(inout) :: neighbour_description
668  type(field_data_wrapper_type), dimension(:), intent(in), optional :: source_data
669 
670  type(field_data_wrapper_type) :: selected_source
671 
672  selected_source=source_data(1)
674  call copy_buffer_to_field(current_state%local_grid, neighbour_description%recv_halo_buffer, selected_source%data, &
675  dim, target_index, current_page(neighbour_location))
676 
677  current_page(neighbour_location)=current_page(neighbour_location)+1
678  end subroutine copy_halo_buffer_to_calc_ax
679 
683  subroutine perform_local_data_copy_for_p(current_state, halo_depth, involve_corners, source_data)
684  type(model_state_type), intent(inout) :: current_state
685  integer, intent(in) :: halo_depth
686  logical, intent(in) :: involve_corners
687  type(field_data_wrapper_type), dimension(:), intent(in), optional :: source_data
688 
689  call perform_local_data_copy_for_field(current_state%p%data, current_state%local_grid, &
690  current_state%parallel%my_rank, halo_depth, involve_corners)
691  end subroutine perform_local_data_copy_for_p
692 
696  subroutine perform_local_data_copy_for_calc_ax(current_state, halo_depth, involve_corners, source_data)
697  type(model_state_type), intent(inout) :: current_state
698  integer, intent(in) :: halo_depth
699  logical, intent(in) :: involve_corners
700  type(field_data_wrapper_type), dimension(:), intent(in), optional :: source_data
701 
702  type(field_data_wrapper_type) :: selected_source
703 
704  selected_source=source_data(1)
705 
706  call perform_local_data_copy_for_field(selected_source%data, current_state%local_grid, &
707  current_state%parallel%my_rank, halo_depth, involve_corners)
709 
713  function create_problem_matrix(z_size)
714  integer, intent(in) :: z_size
715  type(matrix_type) :: create_problem_matrix
716 
717  allocate(create_problem_matrix%u(z_size), create_problem_matrix%d(z_size), create_problem_matrix%p(z_size), &
718  create_problem_matrix%lu_u(z_size), create_problem_matrix%lu_d(z_size), create_problem_matrix%vol(z_size))
719  end function create_problem_matrix
720 
726  subroutine complete_psrce_calculation(current_state, y_halo_size, x_halo_size)
727  type(model_state_type), target, intent(inout) :: current_state
728  integer, intent(in) :: y_halo_size, x_halo_size
729 
730  integer :: ierr, combined_handles(2), i, j, k
731 
732  combined_handles(1)=current_state%psrce_x_hs_recv_request
733  combined_handles(2)=current_state%psrce_y_hs_recv_request
734  call mpi_waitall(2, combined_handles, mpi_statuses_ignore, ierr)
735 
736  do j=current_state%local_grid%local_domain_start_index(y_index), current_state%local_grid%local_domain_end_index(y_index)
737  do k=2,current_state%local_grid%size(z_index)
738 #ifdef U_ACTIVE
739  current_state%p%data(k,j,x_halo_size+1)=current_state%p%data(k,j,x_halo_size+1)-&
740  current_state%psrce_recv_buffer_x(k-1,j-x_halo_size)
741 #endif
742 #ifdef V_ACTIVE
743  if (j .gt. y_halo_size+1) current_state%p%data(k, j, x_halo_size+1)=current_state%p%data(k, j, x_halo_size+1)-&
744  current_state%global_grid%configuration%horizontal%cy * current_state%sv%data(k, j-1, x_halo_size+1)
745 #endif
746  end do
747  end do
748 
749 #ifdef V_ACTIVE
750  do i=current_state%local_grid%local_domain_start_index(x_index), current_state%local_grid%local_domain_end_index(x_index)
751  do k=2,current_state%local_grid%size(z_index)
752  current_state%p%data(k,y_halo_size+1,i)=current_state%p%data(k,y_halo_size+1,i)-&
753  current_state%psrce_recv_buffer_y(k-1,i-y_halo_size)
754  end do
755  end do
756 #endif
757 
758  combined_handles(1)=current_state%psrce_x_hs_send_request
759  combined_handles(2)=current_state%psrce_y_hs_send_request
760  call mpi_waitall(2, combined_handles, mpi_statuses_ignore, ierr)
761  end subroutine complete_psrce_calculation
762 end module iterativesolver_mod
763 
integer, public precision_type
Definition: datadefn.F90:19
subroutine, public init_halo_communication(current_state, get_fields_per_halo_cell, halo_state, halo_depth, involve_corners)
Initialises a halo swapping state, by determining the neighbours, size of data in each swap and alloc...
type(halo_communication_type), save halo_swap_state
The halo swap state as initialised by that module.
real(kind=default_precision) tolerance
subroutine, public blocking_halo_swap(current_state, halo_swap_state, copy_to_halo_buffer, perform_local_data_copy, copy_from_halo_buffer, copy_corners_to_halo_buffer, copy_from_halo_buffer_to_corner, source_data)
Performs the entire halo swap operation, this is simply a wrapper around the nonblocking initiate and...
subroutine finalisation_callback(current_state)
Called as MONC is shutting down and frees the halo swap state and deallocates local data...
subroutine, public perform_local_data_copy_for_field(field_data, local_grid, my_rank, halo_depth, involve_corners)
Will perform a a local copy for the halo data of a field.
subroutine perform_local_data_copy_for_calc_ax(current_state, halo_depth, involve_corners, source_data)
Does a local data copy for halo swapping cells with wrap around (to maintain periodic boundary condit...
integer, parameter, public log_error
Only log ERROR messages.
Definition: logging.F90:11
Contains the types used for communication, holding the state of communications and supporting activit...
subroutine set_matrix_for_poisson(grid_configuration, A, z_size)
Sets the values of the provided matrix to solve the poisson equation.
A helper type to abstract the concrete details of the matrix.
Logging utility.
Definition: logging.F90:2
subroutine deduce_global_divmax(current_state)
Determines the global divmax which is written into the current state.
integer, parameter, public default_precision
MPI communication type which we use for the prognostic and calculation data.
Definition: datadefn.F90:17
integer, parameter, public z_index
Grid index parameters.
Definition: grids.F90:14
subroutine, public complete_nonblocking_halo_swap(current_state, halo_swap_state, perform_local_data_copy, copy_from_halo_buffer, copy_from_halo_buffer_to_corner, source_data)
This completes a nonblocking halo swap and it is only during this call that the data fields themselve...
subroutine initialisation_callback(current_state)
Initialisation callback hook which will set up the halo swapping state and allocate some data...
Contains common definitions for the data and datatypes used by MONC.
Definition: datadefn.F90:2
The ModelState which represents the current state of a run.
Definition: state.F90:39
logical function, public is_component_enabled(options_database, component_name)
Determines whether or not a specific component is registered and enabled.
Definition: registry.F90:334
subroutine, public log_master_log(level, message)
Will log just from the master process.
Definition: logging.F90:47
integer, parameter, public log_debug
Log DEBUG, INFO, WARNING and ERROR messages.
Definition: logging.F90:14
type(matrix_type) a
Conversion between common inbuilt FORTRAN data types.
Definition: conversions.F90:5
Converts data types to strings.
Definition: conversions.F90:36
subroutine, public copy_buffer_to_field(local_grid, halo_buffer, field_data, dim, target_index, halo_page)
Copies the received buffer for a specific field to the corresponding halo data of that prognostic fie...
Wraps the dimensional configuration types.
Definition: grids.F90:94
subroutine, public initiate_nonblocking_halo_swap(current_state, halo_swap_state, copy_to_halo_buffer, copy_corners_to_halo_buffer, source_data)
Initiates a non blocking halo swap, this registers the receive requests, copies data into the send bu...
subroutine, public log_log(level, message, str)
Logs a message at the specified level. If the level is above the current level then the message is ig...
Definition: logging.F90:75
real(kind=default_precision), parameter tiny
Minimum residual - if we go below this then something has gone wrong.
type(component_descriptor_type) function, public iterativesolver_get_descriptor()
Descriptor of the iterative solver component used by the registry.
real(kind=default_precision) function inner_prod(current_state, x, y, i_strt, i_end, j_strt, j_end, k_end)
Returns the global inner product of two vectors, ignoring the halo cells.
subroutine copy_halo_buffer_to_calc_ax(current_state, neighbour_description, dim, target_index, neighbour_location, current_page, source_data)
Copies the halo buffer to halo location for the source field as required in the calc_Ax procedure...
Maintains the state of a halo swap and contains buffers, neighbours etc.
Map data structure that holds string (length 20 maximum) key value pairs.
Definition: collections.F90:86
subroutine copy_halo_buffer_to_p(current_state, neighbour_description, dim, target_index, neighbour_location, current_page, source_data)
Copies the halo buffer to halo location for the p field.
real(kind=default_precision), dimension(:,:,:), allocatable psource
integer function, public get_single_field_per_halo_cell(current_state)
A very common function, which returns a single field per halo cell which is used to halo swap just on...
Interfaces and types that MONC components must specify.
real(kind=default_precision), dimension(:,:,:), allocatable prev_p
Passed to BiCGStab as the RHS.
Defined the local grid, i.e. the grid held on this process after decomposition.
Definition: grids.F90:111
Collection data structures.
Definition: collections.F90:7
subroutine cg_solver(current_state, A, x, b, i_strt, i_end, j_strt, j_end, k_end)
Performs the preconditioned conjugate gradient method.
subroutine perform_local_data_copy_for_p(current_state, halo_depth, involve_corners, source_data)
Does local data copying for P variable halo swap.
Provides the mechanism for halo swapping. This module contains the functionality required to determin...
real(kind=default_precision) relaxation
Solving tollerance.
integer, parameter, public log_warn
Log WARNING and ERROR messages.
Definition: logging.F90:12
Describes the neighbours of a process in a specific dimension and contains the communication buffers ...
subroutine complete_psrce_calculation(current_state, y_halo_size, x_halo_size)
Completes the psrce calculation by waiting on all outstanding psrce communications to complete and th...
This is the iterative pressure solver and uses a Jacobi preconditioned BiCGStab which we implement he...
subroutine precond(current_state, A, s, r, preits)
Jacobi preconditioner.
subroutine, public copy_field_to_buffer(local_grid, halo_buffer, field_data, dim, source_index, halo_page)
Copies prognostic field data to send buffer for specific field, dimension, halo cell.
subroutine bicgstab(current_state, A, x, b, i_strt, i_end, j_strt, j_end, k_end)
Performs the BiCGStab KS method.
subroutine calc_ax(current_state, A, x, Ax)
Calculates A * x.
real(kind=default_precision) function, public options_get_real(options_database, key, index)
Retrieves a real value from the database that matches the provided key.
subroutine copy_p_to_halo_buffer(current_state, neighbour_description, dim, source_index, pid_location, current_page, source_data)
Copies the p field data to halo buffers for a specific process in a dimension and halo cell...
type(matrix_type) function create_problem_matrix(z_size)
Creates a problem matrix, allocating the required data based upon the column size.
Functionality to support the different types of grid and abstraction between global grids and local o...
Definition: grids.F90:5
integer function, public options_get_integer(options_database, key, index)
Retrieves an integer value from the database that matches the provided key.
subroutine, public finalise_halo_communication(halo_swap_state)
Finalises the halo swap represented by the state by freeing up all the allocated memory.
Manages the options database. Contains administration functions and deduce runtime options from the c...
logical function, public options_get_logical(options_database, key, index)
Retrieves a logical value from the database that matches the provided key.
integer preconditioner_iterations
Number of preconditioner iterations to perform per call.
real(kind=default_precision) function, dimension(3) inner_prod_three_way(current_state, t, s, i_strt, i_end, j_strt, j_end, k_end)
Returns the global inner product of a pair of vectors, ignoring the halo cells for three separate pai...
integer max_iterations
Maximum number of BiCGStab iterations.
The model state which represents the current state of a run.
Definition: state.F90:2
integer function, public log_get_logging_level()
Retrieves the current logging level.
Definition: logging.F90:122
integer, parameter, public y_index
Definition: grids.F90:14
integer, parameter, public x_index
Definition: grids.F90:14
subroutine copy_calc_ax_to_halo_buffer(current_state, neighbour_description, dim, source_index, pid_location, current_page, source_data)
Copies the source field data to halo buffers for a specific process in a dimension and halo cell - fo...
MONC component registry.
Definition: registry.F90:5
subroutine timestep_callback(current_state)
Timestep callback, this ignores all but the last column where it calls the solver.