Octopus
multigrid.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch, X. Andrade
2!! Copyright (C) 2021 S. Ohlmann
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
22module multigrid_oct_m
23 use batch_oct_m
26 use debug_oct_m
28 use global_oct_m
29 use index_oct_m
31 use math_oct_m
32 use mesh_oct_m
37 use parser_oct_m
39 use space_oct_m
43
44 implicit none
45
46 private
47 public :: &
64
65 integer, parameter, public :: &
66 INJECTION = 1, &
67 fullweight = 2
68
70 ! Components are public by default
71 type(transfer_table_t) :: tt
72 type(mesh_t), pointer :: mesh => null()
73 type(derivatives_t), pointer :: der => null()
74 end type multigrid_level_t
75
76 type multigrid_t
77 private
78 integer, public :: n_levels
79 type(multigrid_level_t), allocatable, public :: level(:)
80
81 integer :: tp
82 integer, allocatable :: sp(:)
83 integer, allocatable :: ep(:)
84 integer, allocatable :: ep_part(:)
85 end type multigrid_t
86
87
88contains
89
90 ! ---------------------------------------------------------
91 subroutine multigrid_init(mgrid, namespace, space, mesh, der, stencil, mc, nlevels)
92 type(multigrid_t), target, intent(out) :: mgrid
93 type(namespace_t), intent(in) :: namespace
94 class(space_t), intent(in) :: space
95 class(mesh_t), target, intent(in) :: mesh
96 type(derivatives_t), target, intent(in) :: der
97 type(stencil_t), intent(in) :: stencil
98 type(multicomm_t), intent(in) :: mc
99 integer, optional, intent(in) :: nlevels
100
101 integer :: i, n_levels, np, order
102
103 push_sub(multigrid_init)
104
105 if (.not. present(nlevels)) then
106 !%Variable MultigridLevels
107 !%Type integer
108 !%Default 4
109 !%Section Mesh
110 !%Description
111 !% Number of levels in the grid hierarchy used for multigrid. Positive
112 !% numbers indicate an absolute number of levels, negative
113 !% numbers are subtracted from the maximum number of levels possible.
114 !%Option max_levels 0
115 !% Calculate the optimal number of levels for the grid.
116 !%End
117
118 call parse_variable(namespace, 'MultigridLevels', 4, n_levels)
119
120 ! default:
121 order = der%order
122 else
123 n_levels = nlevels
124 write(message(1), '(a,i1,a)') "Set number of multigrid levels to ", n_levels, ". This ignores the value of MultigridLevels."
125 call messages_info(1, namespace=namespace)
126
127 !%Variable MultigridDerivativesOrder
128 !%Type integer
129 !%Default 1
130 !%Section Mesh::Derivatives
131 !%Description
132 !% This variable gives the discretization order for the approximation of
133 !% the differential operators on the different levels of the multigrid.
134 !% For more details, see the variable DerivativesOrder.
135 !% For star-general stencils, the minimum is set to 2.
136 !%End
137 call parse_variable(namespace, 'MultigridDerivativesOrder', 1, order)
138 ! set order to a minimum of 2 for general star stencil, fails otherwise
139 if (der%stencil_type == der_stargeneral) then
140 order = max(2, order)
141 end if
142 end if
143
144 if (n_levels <= 0) then
145 n_levels = n_levels - 3
146 np = mesh%np
147
148 do while (np > 1)
149 np = np / 8
150 n_levels = n_levels + 1
151 end do
152 else
153 n_levels = n_levels - 1
154 end if
155
156 mgrid%n_levels = n_levels
157
158 safe_allocate(mgrid%level(0:n_levels))
159
160 mgrid%level(0)%mesh => mesh
161 mgrid%level(0)%der => der
163 mgrid%level(0)%tt%n_fine = mesh%np
164 safe_allocate(mgrid%level(0)%tt%fine_i(1:mesh%np))
166 write(message(1), '(a,i3)') "Multigrid levels:", n_levels + 1
167 call messages_info(1, namespace=namespace)
168
169 do i = 1, mgrid%n_levels
170 safe_allocate(mgrid%level(i)%mesh)
171 safe_allocate(mgrid%level(i)%der)
173 call multigrid_mesh_half(space, namespace, mgrid%level(i-1)%mesh, mgrid%level(i)%mesh, stencil)
175 call derivatives_init(mgrid%level(i)%der, namespace, space, mesh%coord_system, order=order)
177 call mesh_init_stage_3(mgrid%level(i)%mesh, namespace, space, stencil, mc, parent = mgrid%level(i - 1)%mesh)
178
179 call multigrid_get_transfer_tables(mgrid%level(i)%tt, space, mgrid%level(i-1)%mesh, mgrid%level(i)%mesh)
180
181 call derivatives_build(mgrid%level(i)%der, namespace, space, mgrid%level(i)%mesh)
182
183 call mesh_write_info(mgrid%level(i)%mesh, namespace=namespace)
185 mgrid%level(i)%der%finer => mgrid%level(i - 1)%der
186 mgrid%level(i - 1)%der%coarser => mgrid%level(i)%der
187 mgrid%level(i)%der%to_finer => mgrid%level(i)%tt
188 mgrid%level(i - 1)%der%to_coarser => mgrid%level(i)%tt
189 end do
190
191 safe_allocate(mgrid%sp(0:mgrid%n_levels))
192 safe_allocate(mgrid%ep(0:mgrid%n_levels))
193 safe_allocate(mgrid%ep_part(0:mgrid%n_levels))
194
195 mgrid%tp = 0
196 do i = 0, mgrid%n_levels
197 mgrid%sp(i) = 1 + mgrid%tp
198 mgrid%ep(i) = mgrid%tp + mgrid%level(i)%mesh%np
199 mgrid%tp = mgrid%tp + mgrid%level(i)%mesh%np_part
200 mgrid%ep_part(i) = mgrid%tp
201 end do
202
203 pop_sub(multigrid_init)
204 end subroutine multigrid_init
205
206 ! ---------------------------------------------------------
208 subroutine multigrid_get_transfer_tables(tt, space, fine, coarse)
209 type(transfer_table_t), intent(inout) :: tt
210 class(space_t), intent(in) :: space
211 type(mesh_t), intent(in) :: fine, coarse
212
213 integer :: i, i1, i2, i4, i8, pt
214 integer :: x(space%dim), mod2(space%dim), idx(space%dim)
215
217
218 ! Currently this routine only works for 3D
219 assert(space%dim == 3)
220
221 tt%n_coarse = coarse%np
222 safe_allocate(tt%to_coarse(1:tt%n_coarse))
223
224 ! GENERATE THE TABLE TO MAP FROM THE FINE TO THE COARSE GRID
225 do i = 1, tt%n_coarse
226 ! locate the equivalent fine grid point
227 call mesh_local_index_to_coords(coarse, i, idx)
228 tt%to_coarse(i) = mesh_local_index_from_coords(fine, 2*idx)
229 end do
230
231 ! count
232 tt%n_fine = fine%np
233 safe_allocate(tt%fine_i(1:tt%n_fine))
234
235 tt%n_fine1 = 0
236 tt%n_fine2 = 0
237 tt%n_fine4 = 0
238 tt%n_fine8 = 0
239 do i = 1, tt%n_fine
240 call mesh_local_index_to_coords(fine, i, idx)
241 mod2 = mod(idx, 2)
242
243 pt = sum(abs(mod2))
244
245 select case (pt)
246 case (0)
247 tt%n_fine1 = tt%n_fine1 + 1
248 tt%fine_i(i) = 1
249 case (1)
250 tt%n_fine2 = tt%n_fine2 + 1
251 tt%fine_i(i) = 2
252 case (2)
253 tt%n_fine4 = tt%n_fine4 + 1
254 tt%fine_i(i) = 4
255 case (3)
256 tt%n_fine8 = tt%n_fine8 + 1
257 tt%fine_i(i) = 8
258 end select
259 end do
260
261 assert(tt%n_fine1 + tt%n_fine2 + tt%n_fine4 + tt%n_fine8 == tt%n_fine)
262
263 safe_allocate(tt%to_fine1(1, 1:tt%n_fine1))
264 safe_allocate(tt%to_fine2(1:2, 1:tt%n_fine2))
265 safe_allocate(tt%to_fine4(1:4, 1:tt%n_fine4))
266 safe_allocate(tt%to_fine8(1:8, 1:tt%n_fine8))
267
268 ! and now build the tables
269 i1 = 0
270 i2 = 0
271 i4 = 0
272 i8 = 0
273 do i = 1, fine%np
274 call mesh_local_index_to_coords(fine, i, idx)
275 x = idx/2
276 mod2 = mod(idx, 2)
277
278 pt = sum(abs(mod2))
279
280 select case (pt)
281 case (0)
282 i1 = i1 + 1
283 tt%to_fine1(1, i1) = mesh_local_index_from_coords(coarse, x)
284
285 case (1)
286 i2 = i2 + 1
287 tt%to_fine2(1, i2) = mesh_local_index_from_coords(coarse, x)
288 tt%to_fine2(2, i2) = mesh_local_index_from_coords(coarse, x + mod2)
289
290 case (2)
291 i4 = i4 + 1
292 tt%to_fine4(1, i4) = mesh_local_index_from_coords(coarse, [x(1) , x(2) + mod2(2), x(3) + mod2(3)])
293 tt%to_fine4(2, i4) = mesh_local_index_from_coords(coarse, [x(1) + mod2(1), x(2) , x(3) + mod2(3)])
294 tt%to_fine4(3, i4) = mesh_local_index_from_coords(coarse, [x(1) + mod2(1), x(2) + mod2(2), x(3) ])
295 tt%to_fine4(4, i4) = mesh_local_index_from_coords(coarse, x + mod2)
296
297 case (3)
298 i8 = i8 + 1
299 tt%to_fine8(1, i8) = mesh_local_index_from_coords(coarse, x)
300 tt%to_fine8(2, i8) = mesh_local_index_from_coords(coarse, [x(1) + mod2(1), x(2) , x(3) ])
301 tt%to_fine8(3, i8) = mesh_local_index_from_coords(coarse, [x(1) , x(2) + mod2(2), x(3) ])
302 tt%to_fine8(4, i8) = mesh_local_index_from_coords(coarse, [x(1) , x(2) , x(3) + mod2(3)])
303 tt%to_fine8(5, i8) = mesh_local_index_from_coords(coarse, [x(1) , x(2) + mod2(2), x(3) + mod2(3)])
304 tt%to_fine8(6, i8) = mesh_local_index_from_coords(coarse, [x(1) + mod2(1), x(2) , x(3) + mod2(3)])
305 tt%to_fine8(7, i8) = mesh_local_index_from_coords(coarse, [x(1) + mod2(1), x(2) + mod2(2), x(3) ])
306 tt%to_fine8(8, i8) = mesh_local_index_from_coords(coarse, x + mod2)
307
308 end select
309
310 end do
311
312 assert(i1 == tt%n_fine1 .and. i2 == tt%n_fine2 .and. i4 == tt%n_fine4 .and. i8 == tt%n_fine8)
313
314
316 end subroutine multigrid_get_transfer_tables
317
318 !---------------------------------------------------------------------------------
321 !---------------------------------------------------------------------------------
322 subroutine multigrid_mesh_half(space, namespace, mesh_in, mesh_out, stencil)
323 class(space_t), intent(in) :: space
324 type(namespace_t), intent(in) :: namespace
325 type(mesh_t), target, intent(in) :: mesh_in
326 type(mesh_t), intent(inout) :: mesh_out
327 type(stencil_t), intent(in) :: stencil
328
329 integer :: idim
330
331 push_sub(multigrid_mesh_half)
332
333 mesh_out%box => mesh_in%box
334 mesh_out%idx%dim = mesh_in%idx%dim
335 mesh_out%use_curvilinear = mesh_in%use_curvilinear
336 mesh_out%masked_periodic_boundaries = mesh_in%masked_periodic_boundaries
337 mesh_out%coord_system => mesh_in%coord_system
338
339 safe_allocate(mesh_out%spacing(1:space%dim))
340 mesh_out%spacing(:) = 2*mesh_in%spacing(:)
341
342 call index_init(mesh_out%idx, space%dim)
343 mesh_out%idx%enlarge(:) = mesh_in%idx%enlarge(:)
344 mesh_out%idx%nr(1,:) = (mesh_in%idx%nr(1,:)+mesh_in%idx%enlarge(:))/2
345 mesh_out%idx%nr(2,:) = (mesh_in%idx%nr(2,:)-mesh_in%idx%enlarge(:))/2
346 mesh_out%idx%ll(:) = mesh_out%idx%nr(2, :) - mesh_out%idx%nr(1, :) + 1
347
348 mesh_out%idx%stride(1) = 1
349 do idim = 2, mesh_out%idx%dim + 1
350 mesh_out%idx%stride(idim) = mesh_out%idx%stride(idim-1) * &
351 (mesh_out%idx%ll(idim-1) + 2*mesh_out%idx%enlarge(idim-1))
352 end do
353
354 call mesh_init_stage_2(mesh_out, namespace, space, mesh_out%box, stencil)
355
356 pop_sub(multigrid_mesh_half)
357 end subroutine multigrid_mesh_half
358
359 !---------------------------------------------------------------------------------
360 subroutine multigrid_mesh_double(space, namespace, mesh_in, mesh_out, stencil)
361 class(space_t), intent(in) :: space
362 type(namespace_t), intent(in) :: namespace
363 type(mesh_t), target, intent(in) :: mesh_in
364 type(mesh_t), intent(inout) :: mesh_out
365 type(stencil_t), intent(in) :: stencil
366
367 integer :: idim
368 push_sub(multigrid_mesh_double)
369
370 mesh_out%box => mesh_in%box
371 mesh_out%idx%dim = mesh_in%idx%dim
372 mesh_out%use_curvilinear = mesh_in%use_curvilinear
373 mesh_out%masked_periodic_boundaries = mesh_in%masked_periodic_boundaries
374 mesh_out%coord_system => mesh_in%coord_system
375
376 safe_allocate(mesh_out%spacing(1:space%dim))
377 mesh_out%spacing(:) = m_half*mesh_in%spacing(:)
378
379 call index_init(mesh_out%idx, space%dim)
380 mesh_out%idx%enlarge(:) = mesh_in%idx%enlarge(:)
381 mesh_out%idx%nr(1,:) = (mesh_in%idx%nr(1,:)+mesh_in%idx%enlarge(:))*2
382 mesh_out%idx%nr(2,:) = (mesh_in%idx%nr(2,:)-mesh_in%idx%enlarge(:))*2
383 ! We need to make the possible number of grid points larger by one for
384 ! the non-periodic dimensions because the spacing is only half of the
385 ! original mesh and thus we could get points in the new boundary
386 ! that are still inside the simulation box.
387 ! For the periodic dimensions, we are anyway commensurate with the size
388 ! of the box, so we are still commensurate when taking twice the number
389 ! of points.
390 do idim = space%periodic_dim + 1, space%dim
391 mesh_out%idx%nr(1, idim) = mesh_out%idx%nr(1, idim) - 1
392 mesh_out%idx%nr(2, idim) = mesh_out%idx%nr(2, idim) + 1
393 end do
394 mesh_out%idx%ll(:) = mesh_out%idx%nr(2, :) - mesh_out%idx%nr(1, :) + 1
395
396 mesh_out%idx%stride(1) = 1
397 do idim = 2, space%dim+1
398 mesh_out%idx%stride(idim) = mesh_out%idx%stride(idim-1) * &
399 (mesh_out%idx%ll(idim-1) + 2*mesh_out%idx%enlarge(idim-1))
400 end do
401
402 call mesh_init_stage_2(mesh_out, namespace, space, mesh_out%box, stencil)
403
404 pop_sub(multigrid_mesh_double)
405 end subroutine multigrid_mesh_double
406
407 ! ---------------------------------------------------------
408 subroutine multigrid_end(mgrid)
409 type(multigrid_t), target, intent(inout) :: mgrid
410
411 integer :: i
412 type(multigrid_level_t), pointer :: level
413
414 push_sub(multigrid_end)
416 safe_deallocate_a(mgrid%sp)
417 safe_deallocate_a(mgrid%ep)
418 safe_deallocate_a(mgrid%ep_part)
419
420 safe_deallocate_a(mgrid%level(0)%tt%fine_i)
421
422 do i = 1, mgrid%n_levels
423 level => mgrid%level(i)
424
425 call derivatives_end(level%der)
426 call mesh_end(level%mesh)
427 safe_deallocate_p(level%mesh)
428 safe_deallocate_p(level%der)
429
430 safe_deallocate_a(level%tt%to_coarse)
431 safe_deallocate_a(level%tt%to_fine1)
432 safe_deallocate_a(level%tt%to_fine2)
433 safe_deallocate_a(level%tt%to_fine4)
434 safe_deallocate_a(level%tt%to_fine8)
435 safe_deallocate_a(level%tt%fine_i)
436 end do
437
438 safe_deallocate_a(mgrid%level)
439
440 pop_sub(multigrid_end)
441 end subroutine multigrid_end
442
443 !---------------------------------------------------------------------------------
444 integer function multigrid_number_of_levels(base_der) result(number)
445 type(derivatives_t), target, intent(in) :: base_der
446
447 type(derivatives_t), pointer :: next_der
448
449 next_der => base_der%coarser
450
451 number = 0
452 do
453 number = number + 1
454 next_der => next_der%coarser
455 if (.not. associated(next_der)) exit
456 end do
457
458 end function multigrid_number_of_levels
459
460 !---------------------------------------------------------------------------------
461 subroutine multigrid_build_stencil(dim, weight, shift)
462 integer, intent(in) :: dim
463 real(real64), intent(inout) :: weight(:)
464 integer, intent(inout) :: shift(:,:)
465
466 integer :: nn, di, dj, dk, dd
467
469
470 assert(ubound(weight, dim=1) == 3**dim)
471 assert(ubound(shift, dim=1) == dim)
472 assert(ubound(shift, dim=2) == 3**dim)
473
474 nn = 0
475 select case(dim)
476 case(1)
477 do di = -1, 1
478 dd = abs(di)
479 nn = nn + 1
480 weight(nn) = m_half**dd
481 shift(1,nn) = di
482 end do
483 case(2)
484 do di = -1, 1
485 do dj = -1, 1
486 dd = abs(di)+abs(dj)
487 nn = nn + 1
488 weight(nn) = m_half**dd
489 shift(1,nn) = di
490 shift(2,nn) = dj
491 end do
492 end do
493 case(3)
494 do di = -1, 1
495 do dj = -1, 1
496 do dk = -1, 1
497 dd = abs(di)+abs(dj)+abs(dk)
498 nn = nn + 1
499 weight(nn) = m_half**dd
500 shift(1,nn) = di
501 shift(2,nn) = dj
502 shift(3,nn) = dk
503 end do
504 end do
505 end do
506 end select
507
509 end subroutine multigrid_build_stencil
510
511
512#include "undef.F90"
513#include "real.F90"
514#include "multigrid_inc.F90"
515
516#include "undef.F90"
517#include "complex.F90"
518#include "multigrid_inc.F90"
519
520end module multigrid_oct_m
521
522!! Local Variables:
523!! mode: f90
524!! coding: utf-8
525!! End:
This module implements batches of mesh functions.
Definition: batch.F90:133
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:122
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public derivatives_build(der, namespace, space, mesh, qvector, regenerate, verbose)
build the derivatives object:
subroutine, public derivatives_init(der, namespace, space, coord_system, order)
subroutine, public derivatives_end(der)
integer, parameter, public der_stargeneral
real(real64), parameter, public m_half
Definition: global.F90:193
This module implements the index, used for the mesh points.
Definition: index.F90:122
subroutine, public index_init(idx, dim)
This subroutine allocates memory and initializes some components.
Definition: index.F90:218
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
This module contains subroutines, related to the initialization of the mesh.
Definition: mesh_init.F90:117
subroutine, public mesh_init_stage_3(mesh, namespace, space, stencil, mc, parent, regenerate)
When running parallel in domains, stencil and np_stencil are needed to compute the ghost points....
Definition: mesh_init.F90:538
subroutine, public mesh_init_stage_2(mesh, namespace, space, box, stencil, regenerate)
This subroutine creates the global array of spatial indices and the inverse mapping.
Definition: mesh_init.F90:290
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
integer function, public mesh_local_index_from_coords(mesh, ix)
This function returns the local index of the point for a given vector of integer coordinates.
Definition: mesh.F90:935
subroutine, public mesh_write_info(this, iunit, namespace)
Definition: mesh.F90:304
subroutine, public mesh_local_index_to_coords(mesh, ip, ix)
Given a local point index, this function returns the set of integer coordinates of the point.
Definition: mesh.F90:947
recursive subroutine, public mesh_end(this)
Definition: mesh.F90:680
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
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
subroutine, public multigrid_mesh_double(space, namespace, mesh_in, mesh_out, stencil)
Definition: multigrid.F90:454
subroutine, public dmultigrid_fine2coarse_batch(tt, fine_der, coarse_mesh, fineb, coarseb, method_p)
Definition: multigrid.F90:972
subroutine, public dmultigrid_coarse2fine(tt, coarse_der, fine_mesh, f_coarse, f_fine, set_bc)
Definition: multigrid.F90:674
integer function, public multigrid_number_of_levels(base_der)
Definition: multigrid.F90:538
subroutine, public multigrid_end(mgrid)
Definition: multigrid.F90:502
subroutine, public dmultigrid_fine2coarse(tt, fine_der, coarse_mesh, f_fine, f_coarse, method_p)
Definition: multigrid.F90:753
integer, parameter, public fullweight
Definition: multigrid.F90:158
subroutine, public zmultigrid_fine2coarse_batch(tt, fine_der, coarse_mesh, fineb, coarseb, method_p)
Definition: multigrid.F90:1483
subroutine, public zmultigrid_coarse2fine(tt, coarse_der, fine_mesh, f_coarse, f_fine, set_bc)
Definition: multigrid.F90:1185
subroutine, public multigrid_mesh_half(space, namespace, mesh_in, mesh_out, stencil)
Creates a mesh that has twice the spacing betwen the points than the in mesh. This is used in the mul...
Definition: multigrid.F90:416
subroutine, public multigrid_init(mgrid, namespace, space, mesh, der, stencil, mc, nlevels)
Definition: multigrid.F90:185
subroutine, public zmultigrid_fine2coarse(tt, fine_der, coarse_mesh, f_fine, f_coarse, method_p)
Definition: multigrid.F90:1264
subroutine, public dmultigrid_coarse2fine_batch(tt, coarse_der, fine_mesh, coarseb, fineb)
Definition: multigrid.F90:868
subroutine multigrid_build_stencil(dim, weight, shift)
Definition: multigrid.F90:555
subroutine, public multigrid_get_transfer_tables(tt, space, fine, coarse)
creates the lookup tables to go between the coarse and fine meshes
Definition: multigrid.F90:302
subroutine, public zmultigrid_coarse2fine_batch(tt, coarse_der, fine_mesh, coarseb, fineb)
Definition: multigrid.F90:1379
Some general things and nomenclature:
Definition: par_vec.F90:171
This module defines stencils used in Octopus.
Definition: stencil.F90:135
class representing derivatives
Describes mesh distribution to nodes.
Definition: mesh.F90:186
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:163