Octopus
multigrid_solver.F90
Go to the documentation of this file.
1!! Copyright (C) 2005-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch, X. Andrade
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
24 use debug_oct_m
26 use global_oct_m
27 use, intrinsic :: iso_fortran_env
29 use mesh_oct_m
36 use parser_oct_m
39 use space_oct_m
41
42 implicit none
43
44 integer, parameter :: &
45 GAUSS_SEIDEL = 1, &
46 gauss_jacobi = 2
47
48 private
49 public :: &
53
54 type mg_solver_t
55 private
56
57 real(real64), public :: threshold
58 real(real64) :: relax_factor
59
60 integer, public :: maxcycles = 0
61 integer :: presteps
62 integer :: poststeps
63 integer :: restriction_method
64 integer :: relaxation_method
65 end type mg_solver_t
66
67contains
68
69 ! ---------------------------------------------------------
70 subroutine multigrid_solver_init(this, namespace, space, mesh, thr)
71 type(mg_solver_t), intent(out) :: this
72 type(namespace_t), intent(in) :: namespace
73 class(space_t), intent(in) :: space
74 type(mesh_t), intent(inout) :: mesh
75 real(real64), intent(in) :: thr
76
77 push_sub(multigrid_solver_init)
78
79 this%threshold = thr
80
81 !%Variable MultigridPresmoothingSteps
82 !%Type integer
83 !%Default 1
84 !%Section Hamiltonian::Poisson::Multigrid
85 !%Description
86 !% Number of Gauss-Seidel smoothing steps before coarse-level
87 !% correction in the multigrid solver.
88 !%End
89 call parse_variable(namespace, 'MultigridPresmoothingSteps', 1, this%presteps)
90
91 !%Variable MultigridPostsmoothingSteps
92 !%Type integer
93 !%Default 4
94 !%Section Hamiltonian::Poisson::Multigrid
95 !%Description
96 !% Number of Gauss-Seidel smoothing steps after coarse-level
97 !% correction in the multigrid solver.
98 !%End
99 call parse_variable(namespace, 'MultigridPostsmoothingSteps', 4, this%poststeps)
100
101 !%Variable MultigridMaxCycles
102 !%Type integer
103 !%Default 50
104 !%Section Hamiltonian::Poisson::Multigrid
105 !%Description
106 !% Maximum number of multigrid cycles that are performed if
107 !% convergence is not achieved.
108 !%End
109 call parse_variable(namespace, 'MultigridMaxCycles', 50, this%maxcycles)
110
111 !%Variable MultigridRestrictionMethod
112 !%Type integer
113 !%Default fullweight
114 !%Section Hamiltonian::Poisson::Multigrid
115 !%Description
116 !% Method used from fine-to-coarse grid transfer.
117 !%Option injection 1
118 !% Injection
119 !%Option fullweight 2
120 !% Fullweight restriction
121 !%End
122 call parse_variable(namespace, 'MultigridRestrictionMethod', 2, this%restriction_method)
123 if (.not. varinfo_valid_option('MultigridRestrictionMethod', this%restriction_method)) then
124 call messages_input_error(namespace, 'MultigridRestrictionMethod')
125 end if
126 call messages_print_var_option("MultigridRestrictionMethod", this%restriction_method, namespace=namespace)
127
128 !%Variable MultigridRelaxationMethod
129 !%Type integer
130 !%Section Hamiltonian::Poisson::Multigrid
131 !%Description
132 !% Method used to solve the linear system approximately in each grid for the
133 !% multigrid procedure that solves a linear equation like the Poisson equation. Default is <tt>gauss_seidel</tt>,
134 !% unless curvilinear coordinates are used, in which case the default is <tt>gauss_jacobi</tt>.
135 !%Option gauss_seidel 1
136 !% Gauss-Seidel.
137 !%Option gauss_jacobi 2
138 !% Gauss-Jacobi.
139 !%End
140 if (mesh%use_curvilinear) then
141 call parse_variable(namespace, 'MultigridRelaxationMethod', gauss_jacobi, this%relaxation_method)
142 else
143 call parse_variable(namespace, 'MultigridRelaxationMethod', gauss_seidel, this%relaxation_method)
144 end if
145
146 if (.not. varinfo_valid_option('MultigridRelaxationMethod', this%relaxation_method)) then
147 call messages_input_error(namespace, 'MultigridRelaxationMethod')
148 end if
149 call messages_print_var_option("MultigridRelaxationMethod", this%relaxation_method, namespace=namespace)
151 !%Variable MultigridRelaxationFactor
152 !%Type float
153 !%Section Hamiltonian::Poisson::Multigrid
154 !%Description
155 !% Relaxation factor of the relaxation operator used for the
156 !% multigrid method. This is mainly for debugging,
157 !% since overrelaxation does not help in a multigrid scheme.
158 !% The default is 1.0, except 0.6666 for the <tt>gauss_jacobi</tt> method.
159 !%End
160 if (this%relaxation_method == gauss_jacobi) then
161 call parse_variable(namespace, 'MultigridRelaxationFactor', 0.6666_real64, this%relax_factor)
162 else
163 call parse_variable(namespace, 'MultigridRelaxationFactor', m_one, this%relax_factor)
164 end if
165
166 pop_sub(multigrid_solver_init)
167 end subroutine multigrid_solver_init
168
169
170 ! ---------------------------------------------------------
174 recursive subroutine multigrid_solver_cycle(this, der, op, sol, rhs)
175 type(mg_solver_t), intent(in) :: this
176 type(derivatives_t), intent(in) :: der
177 type(nl_operator_t), intent(in) :: op
178 real(real64), contiguous, intent(inout) :: sol(:)
179 real(real64), contiguous, intent(in) :: rhs(:)
180
181 integer :: ip, iter
182 real(real64) :: resnorm
183 real(real64), allocatable :: residue(:), coarse_residue(:), correction(:), coarse_correction(:)
184
185 push_sub(multigrid_solver_cycle)
186
187 safe_allocate(residue(1:der%mesh%np_part))
188
189 if (associated(der%coarser)) then
190 assert(associated(op%coarser))
191
192 safe_allocate(correction(1:der%mesh%np_part))
193 safe_allocate(coarse_residue(1:der%coarser%mesh%np_part))
194 safe_allocate(coarse_correction(1:der%coarser%mesh%np_part))
195
196 if (debug%info) then
197 message(1) = "Multigrid restriction"
198 call messages_info(1)
199 end if
200 call multigrid_relax(this, der%mesh, der, op, sol, rhs, this%presteps)
201
202 call get_residual()
203
204 call dmultigrid_fine2coarse(der%to_coarser, der, der%coarser%mesh, residue, coarse_residue, this%restriction_method)
205
206 coarse_correction = m_zero
207 call multigrid_solver_cycle(this, der%coarser, op%coarser, coarse_correction, coarse_residue)
208
209 if (debug%info) then
210 message(1) = "Multigrid prolongation"
211 call messages_info(1)
212 end if
213 correction = m_zero
214 call dmultigrid_coarse2fine(der%to_coarser, der%coarser, der%mesh, coarse_correction, correction)
215
216 call lalg_axpy(der%mesh%np, m_one, correction, sol)
217
218 safe_deallocate_a(correction)
219 safe_deallocate_a(coarse_residue)
220 safe_deallocate_a(coarse_correction)
221
222 call multigrid_relax(this, der%mesh, der, op, sol, rhs, this%poststeps)
223
224 else ! Coarsest grid
225
226
227 do iter = 1, this%maxcycles
228
229 call multigrid_relax(this, der%mesh, der, op, sol, rhs, this%presteps + this%poststeps)
230
231 call get_residual()
232
233 resnorm = dmf_nrm2(der%mesh, residue)
234 if (resnorm < this%threshold) exit
235
236 end do
237
238 if (debug%info) then
239 write(message(1), '(a,i4,a)') "Multigrid coarsest grid solver converged in ", iter, " iterations."
240 write(message(2), '(a,es18.6)') "Residue norm is ", resnorm
241 call messages_info(2)
242 end if
243
244 end if
245
246 safe_deallocate_a(residue)
247
249
250 contains
251
252 subroutine get_residual()
253 ! Compute the residue
254 call dderivatives_perform(op, der, sol, residue)
255 !$omp parallel do
256 do ip = 1, der%mesh%np
257 residue(ip) = rhs(ip) - residue(ip)
258 end do
259 end subroutine get_residual
260
261 end subroutine multigrid_solver_cycle
262
263 ! ---------------------------------------------------------
267 subroutine multigrid_relax(this, mesh, der, op, sol, rhs, steps)
268 type(mg_solver_t), intent(in) :: this
269 type(mesh_t), intent(in) :: mesh
270 type(derivatives_t), intent(in) :: der
271 type(nl_operator_t), intent(in) :: op
272 real(real64), contiguous, intent(inout) :: sol(:)
273 real(real64), contiguous, intent(in) :: rhs(:)
274 integer, intent(in) :: steps
275
276 integer :: istep
277 integer :: ip, nn
278 real(real64) :: point, factor
279 real(real64), allocatable :: op_sol(:), diag(:)
280
281 push_sub(multigrid_relax)
282 call profiling_in("MG_GAUSS_SEIDEL")
283
284 select case (this%relaxation_method)
285
286 case (gauss_seidel)
287
288 do istep = 1, steps
289
290 call boundaries_set(der%boundaries, der%mesh, sol)
291
292 if (mesh%parallel_in_domains) then
293 call dpar_vec_ghost_update(mesh%pv, sol)
294 end if
295
296 nn = op%stencil%size
297
298 if (op%const_w) then
299 factor = -m_one/op%w(op%stencil%center, 1)*this%relax_factor
300 call dgauss_seidel(op%stencil%size, op%w(1, 1), op%nri, &
301 op%ri(1, 1), op%rimap_inv(1), op%rimap_inv(2), factor, sol(1), rhs(1))
302 else
303 !$omp parallel do private(point)
304 do ip = 1, mesh%np
305 point = sum(op%w(1:nn, ip)*sol(op%index(1:nn, ip)))
306 sol(ip) = sol(ip) - this%relax_factor/op%w(op%stencil%center, ip)*(point-rhs(ip))
307 end do
308 end if
309
310 end do
311 call profiling_count_operations(mesh%np*(steps + 1)*(2*nn + 3))
312
313 case (gauss_jacobi)
314
315 safe_allocate(op_sol(1:mesh%np))
316 safe_allocate(diag(1:mesh%np))
317
318 call dnl_operator_operate_diag(op, diag)
319 !$omp parallel do
320 do ip = 1, mesh%np
321 diag(ip) = this%relax_factor/diag(ip)
322 end do
323
324 do istep = 1, steps
325 call dderivatives_perform(op, der, sol, op_sol)
326 !$omp parallel do
327 do ip = 1, mesh%np
328 sol(ip) = sol(ip) - diag(ip)*(op_sol(ip) - rhs(ip))
329 end do
330 end do
331
332 safe_deallocate_a(diag)
333 safe_deallocate_a(op_sol)
334
335 end select
336
337 call profiling_out("MG_GAUSS_SEIDEL")
338 pop_sub(multigrid_relax)
339
340 end subroutine multigrid_relax
341
342end module multigrid_solver_oct_m
343
344!! Local Variables:
345!! mode: f90
346!! coding: utf-8
347!! End:
constant times a vector plus a vector
Definition: lalg_basic.F90:170
subroutine get_residual()
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:122
subroutine, public dpar_vec_ghost_update(pv, v_local)
Updates ghost points of every node.
type(debug_t), save, public debug
Definition: debug.F90:151
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public dderivatives_perform(op, der, ff, op_ff, ghost_update, set_bc, factor)
apply a nl_operator to a mesh function
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_one
Definition: global.F90:188
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
subroutine, public dmultigrid_fine2coarse(tt, fine_der, coarse_mesh, f_fine, f_coarse, method_p)
Definition: multigrid.F90:703
subroutine, public dmultigrid_coarse2fine(tt, coarse_der, fine_mesh, f_coarse, f_fine, order, set_bc)
Definition: multigrid.F90:622
This modules provides the routines for solving Ax=b using the V-shaped multigrid method.
integer, parameter gauss_jacobi
recursive subroutine, public multigrid_solver_cycle(this, der, op, sol, rhs)
Performs one cycle of a V-shaped multigrid solver.
subroutine, public multigrid_solver_init(this, namespace, space, mesh, thr)
subroutine multigrid_relax(this, mesh, der, op, sol, rhs, steps)
Given a nonlocal operator op, perform the relaxation operator.
This module defines non-local operators.
subroutine, public dnl_operator_operate_diag(op, fo)
This module contains interfaces for routines in operate.c.
Definition: operate_f.F90:117
Some general things and nomenclature:
Definition: par_vec.F90:171
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:623
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:552
class representing derivatives
Describes mesh distribution to nodes.
Definition: mesh.F90:185
data type for non local operators