Octopus
regridding.F90
Go to the documentation of this file.
1!! Copyright (C) 2022, 2024 F. Bonafé, S. Ohlmann
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#include "global.h"
19
20
80 use debug_oct_m
81 use global_oct_m
82 use grid_oct_m
83 use iihash_oct_m
85 use math_oct_m
86 use mesh_oct_m
90 use parser_oct_m
94 use space_oct_m
96 use utils_oct_m
97
98 implicit none
99 public :: regridding_t
100
103 type :: regridding_t
104 private
105 class(mesh_t), pointer :: mesh_in, mesh_out
106 type(partition_transfer_t) :: partition_transfer
107 integer :: nsend, nrecv, dim
108 integer, allocatable :: order_in(:), order_out(:)
109 integer(int64), allocatable :: order_in_global(:), order_out_global(:)
110 logical, allocatable :: overlap_map(:)
111 logical :: do_restriction, do_prolongation
112 type(stencil_t) :: transfer_stencil
113 real(real64), allocatable :: weights(:)
114 real(real64), allocatable :: weights_generic(:, :)
115 integer, allocatable :: stencil_points(:, :)
116 integer, allocatable :: eta(:)
117 integer :: interpolation_level
118 integer :: scale_norms
119 logical :: generic_interpolation
120 contains
121 procedure :: dregridding_do_transfer_1, zregridding_do_transfer_1
122 procedure :: dregridding_do_transfer_2, zregridding_do_transfer_2
123 generic :: do_transfer => dregridding_do_transfer_1, zregridding_do_transfer_1
124 generic :: do_transfer => dregridding_do_transfer_2, zregridding_do_transfer_2
125 final :: regridding_finalize
126 end type regridding_t
127
128 interface regridding_t
129 procedure regridding_init
130 end interface regridding_t
131
132 integer, parameter :: &
133 NEAREST_NEIGHBOR = 0, &
134 linear = 1, &
135 scale_none = 0, &
136 scale_norm2 = 1
137
138contains
139
140 ! ---------------------------------------------------------
142 function regridding_init(mesh_out, mesh_in, space_in, namespace) result(this)
143 class(mesh_t), target, intent(in) :: mesh_out
144 class(mesh_t), target, intent(in) :: mesh_in
145 class(space_t), intent(in) :: space_in
146 type(namespace_t), intent(in) :: namespace
147 class(regridding_t), pointer :: this
148
149 integer :: ip_in, ip_out, index(1:space_in%dim), idim, ii, is, size_array
150 integer(int64), allocatable :: global_indices_in(:), order_in(:), order_out(:)
151 integer(int64), allocatable :: order_in_original(:), order_out_original(:)
152 integer(int64), allocatable :: global_indices_in_tmp(:)
153 integer(int64), allocatable :: global_indices_in_original(:)
154 integer, allocatable :: partition_in(:)
155 integer(int64) :: ipg_coarse, ipg_in
156 real(real64) :: spacing_ratio(1:space_in%dim)
157 real(real64) :: x_fine(1:space_in%dim), x_coarse(1:space_in%dim), x_primitive(1:space_in%dim)
158 real(real64) :: x_out(1:space_in%dim), x_in(1:space_in%dim), rmin, r_current
159 real(real64), allocatable :: M(:, :), p(:)
160 real(real64) :: scaling(1:space_in%dim, 1:space_in%dim), rotation(1:space_in%dim, 1:space_in%dim)
161 integer :: i_coarse, ip_fine, ip_mindist, cube_size
162 integer :: index_stencil(1:space_in%dim), shift(1:space_in%dim)
163 logical :: same_eta, on_coarse_grid, found, on_in_grid
164 type(lihash_t) :: global_indices
165 class(mesh_t), pointer :: mesh_coarse, mesh_fine
166 class(coordinate_system_t), pointer :: coarse_coord, fine_coord
167
168 push_sub_with_profile(regridding_init)
169
170 safe_allocate(this)
171
172 nullify(coarse_coord)
173 nullify(fine_coord)
174
175 !%Variable RegriddingInterpolationLevel
176 !%Type integer
177 !%Default regridding_linear
178 !%Section Mesh
179 !%Description
180 !% Choose the interpolation order for the regridding. 0 is equivalent to nearest neighbor
181 !% interpolation. The default is linear interpolation.
182 !%Option regridding_nearest_neighbor 0
183 !% Use the nearest neighbor for the regridding. This is faster than the linear interpolation.
184 !%Option regridding_linear 1
185 !% Use a trilinear interpolation. This is implemented similar to restriction and prolongation
186 !% operations in multigrid methods. This ensures that both directions are adjoint to each other.
187 !%End
188 call parse_variable(namespace, "RegriddingInterpolationLevel", linear, this%interpolation_level)
189
190 !%Variable RegriddingRescale
191 !%Type integer
192 !%Default scale_norm2
193 !%Section Mesh
194 !%Description
195 !% Rescale the regridded quantities. Not using a rescaling can lead to bad results if the
196 !% ratio of the grid spacings is large. The default is to rescale by the 2-norm of the quantity
197 !% except for generic interpolations (i.e. between curvilinear or non-commensurate grids).
198 !%Option scale_none 0
199 !% Do not rescale the regridded quantities.
200 !%Option scale_norm2 1
201 !% Scale the regridded quantities by the 2-norm of the quantity on the overlapping
202 !% region of the grid.
203 !%End
204 call parse_variable(namespace, "RegriddingRescale", scale_norm2, this%scale_norms)
206 ! check some conditions which are not yet supported
207 if (.not. (mesh_out%coord_system%dim == space_in%dim)) then
208 message(1) = "For regridding, both grids need to have the same space dimension."
209 call messages_fatal(1, namespace=namespace)
210 end if
211 ! use generic interpolation if the grids are not commensurate or curvilinear
212 this%generic_interpolation = mesh_out%coord_system%local_basis .or. &
213 mesh_in%coord_system%local_basis .or. &
214 .not. (same_type_as(mesh_out%coord_system, mesh_in%coord_system))
215
216 this%dim = space_in%dim
217 spacing_ratio(:) = mesh_out%spacing(1:this%dim)/mesh_in%spacing(1:this%dim)
219 this%do_restriction = all(spacing_ratio > m_one)
220 this%do_prolongation = all(spacing_ratio < m_one)
221 ! invert spacing ratio for prolongations
222 if (this%do_prolongation) spacing_ratio = m_one/spacing_ratio
223 ! get the integer ratio of the spacings
224 safe_allocate(this%eta(1:this%dim))
225 do idim = 1, this%dim
226 this%eta(idim) = nint(spacing_ratio(idim))
227 end do
228 if (any(abs((spacing_ratio - this%eta)/spacing_ratio) > 10.0_real64*m_epsilon)) then
229 this%generic_interpolation = .true.
230 end if
231 same_eta = .true.
232 do idim = 2, this%dim
233 same_eta = same_eta .and. this%eta(idim) == this%eta(idim-1)
234 end do
235 if (.not. same_eta) then
236 this%generic_interpolation = .true.
237 end if
238 ! use always generic interpolation for nearest neighbor interpolation
239 if (this%interpolation_level == nearest_neighbor) then
240 this%generic_interpolation = .true.
241 end if
242
243 if (this%generic_interpolation) then
244 ! Generic interpolation samples the input at the points of the output and does not
245 ! integrate, so a quantity from a finer input mesh silently loses the values between
246 ! those points. Warn in that case; anisotropic ratios reach this path by construction.
247 if (any(mesh_out%spacing(1:this%dim) > mesh_in%spacing(1:this%dim))) then
248 write(message(1), '(a)') "Regridding falls back to generic interpolation between meshes"
249 write(message(2), '(a)') "whose spacings differ non-uniformly, and the input mesh is finer"
250 write(message(3), '(a)') "in at least one direction. The transfer interpolates (samples) the input at"
251 write(message(4), '(a)') "the output points instead of averaging over output cells."
252 call messages_warning(4, namespace=namespace)
253 end if
254 this%do_prolongation = .true.
255 this%do_restriction = .false.
256 this%scale_norms = scale_none
257 end if
258
259 this%mesh_in => mesh_in
260 this%mesh_out => mesh_out
261 if (.not. this%do_prolongation) then
262 mesh_fine => this%mesh_in
263 mesh_coarse => this%mesh_out
264 else
265 mesh_coarse => this%mesh_in
266 mesh_fine => this%mesh_out
267 end if
268
269 ! collect all locally available points in mesh_coarse that are also in mesh_fine
270 call lihash_init(global_indices)
271 size_array = mesh_fine%np
272 safe_allocate(global_indices_in_tmp(size_array))
273 safe_allocate(global_indices_in_original(size_array))
274
275 if (.not. this%generic_interpolation) then
276 ii = 0
277 do ip_fine = 1, mesh_fine%np
278 call mesh_local_index_to_coords(mesh_fine, ip_fine, index)
279 on_coarse_grid = .true.
280 if (this%do_restriction .or. this%do_prolongation) then
281 do idim = 1, this%dim
282 on_coarse_grid = on_coarse_grid .and. mod(index(idim), this%eta(idim)) == 0
283 end do
284 end if
285 if (on_coarse_grid) then
286 ! translate between fine and coarse grid
287 index(:) = index(:) / this%eta(:)
288 ipg_coarse = mesh_global_index_from_coords(mesh_coarse, index)
289 call insert_global_point(mesh_coarse, ipg_coarse, ii)
290 else if (this%do_restriction .or. this%do_prolongation) then
291 ! now get all coarse points that surround the fine point
292 ! start always from the same corner of the cube
293 ! need a cube of size of the interpolation level, so shift to the corner of that cube
294 index(:) = floor(real(index(:)) / this%eta(:)) - (this%interpolation_level-1)/2
295 cube_size = 1+this%interpolation_level
296 do is = 1, cube_size**this%dim
297 ! get index of coarse point in the surrounding parallelepiped
298 ! using the corresponding index as number in base cube_size
299 call convert_to_base(is-1, cube_size, shift)
300 index_stencil(:) = index(:) + shift(:)
301 ipg_coarse = mesh_global_index_from_coords(mesh_coarse, index_stencil)
302 call insert_global_point(mesh_coarse, ipg_coarse, ii)
303 end do
304 end if
305 end do
306 call lihash_end(global_indices)
307 else
308 ii = 0
309 do ip_out = 1, mesh_out%np
310 call mesh_local_index_to_coords(mesh_out, ip_out, index)
311 x_out = mesh_out%coord_system%to_cartesian(real(index, real64)*mesh_out%spacing)
312 x_in = mesh_in%coord_system%from_cartesian(x_out)/mesh_in%spacing
313 on_in_grid = all(abs((x_in - nint(x_in))) < 10.0_real64*m_epsilon)
314 if (on_in_grid) then
315 ! translate between out and in grid
316 ipg_in = mesh_global_index_from_coords(mesh_in, nint(x_in))
317 call insert_global_point(mesh_in, ipg_in, ii)
318 else
319 ! now get all points in the input mesh that surround the point in the output mesh
320 ! start always from the same corner of the cube
321 ! need a cube of size of the interpolation level, so shift to the corner of that cube
322 index(:) = floor(x_in) - (max(this%interpolation_level, 1)-1)/2
323 cube_size = 1+max(this%interpolation_level, 1)
324 do is = 1, cube_size**this%dim
325 ! get index of coarse point in the surrounding parallelepiped
326 ! using the corresponding index as number in base cube_size
327 call convert_to_base(is-1, cube_size, shift)
328 index_stencil(:) = index(:) + shift(:)
329 ipg_in = mesh_global_index_from_coords(mesh_in, index_stencil)
330 call insert_global_point(mesh_in, ipg_in, ii)
331 end do
332 end if
333 end do
334 call lihash_end(global_indices)
335 end if
336
337 safe_allocate(global_indices_in(ii))
338 safe_allocate(partition_in(ii))
339 global_indices_in(1:ii) = global_indices_in_tmp(1:ii)
340 safe_deallocate_a(global_indices_in_tmp)
341
342 if (mesh_coarse%parallel_in_domains) then
343 ! determine where the points of the coarse mesh are stored
344 call partition_get_partition_number(mesh_coarse%partition, ii, global_indices_in, partition_in)
345 else
346 partition_in = 1
347 end if
348
349 ! Init partition transfer
350 ! need inverse direction for prolongations
351 call partition_transfer_init(this%partition_transfer, ii, global_indices_in, &
352 mesh_in%mpi_grp, mesh_out%mpi_grp, partition_in, &
353 this%nsend, this%nrecv, order_in, order_out, inverse=this%do_prolongation)
354
355 ! we need to transfer the global indices of the boundary point and the corresponding
356 ! inner point for periodic meshes
357 if (space_in%is_periodic()) then
358 global_indices_in(1:ii) = global_indices_in_original(1:ii)
359 call partition_transfer_init(this%partition_transfer, ii, global_indices_in, &
360 mesh_in%mpi_grp, mesh_out%mpi_grp, partition_in, &
361 this%nsend, this%nrecv, order_in_original, order_out_original, inverse=this%do_prolongation)
362 else
363 order_in_original = order_in
364 order_out_original = order_out
365 end if
366
367 ! convert from global to local indices
368 safe_allocate(this%order_in(1:this%nsend))
369 safe_allocate(this%order_in_global(1:this%nsend))
370 safe_allocate(this%order_out(1:this%nrecv))
371 safe_allocate(this%order_out_global(1:this%nrecv))
372
373 ! get the mapping for mesh_in in the order given by the global indices of mesh_out
374 do ip_in = 1, this%nsend
375 if (this%do_restriction) then
376 ! in this case, we have an index on mesh_out
377 this%order_in_global(ip_in) = order_in_original(ip_in)
378 this%order_in(ip_in) = 0
379 else if (this%do_prolongation) then
380 ! in this case, we have an index on mesh_in
381 this%order_in_global(ip_in) = order_in(ip_in)
382 this%order_in(ip_in) = mesh_global2local(mesh_in, this%order_in_global(ip_in))
383 else
384 ! convert back from the global index of mesh_out to a local index of mesh_in
385 call mesh_global_index_to_coords(mesh_out, order_in_original(ip_in), index)
386 this%order_in_global(ip_in) = mesh_global_index_from_coords(mesh_in, index)
387 this%order_in(ip_in) = mesh_global2local(mesh_in, this%order_in_global(ip_in))
388 end if
389 if (.not. this%do_restriction) then
390 if (this%order_in(ip_in) == 0) then
391 write(message(1),'(a,i10,a,i10)') "Error in regridding part 1: mesh point ", &
392 this%order_in(ip_in), " is not stored in partition ", mesh_in%pv%partno
393 call messages_fatal(1, namespace=namespace)
394 end if
395 end if
396 end do
397
398 ! for mapping back to the global grid after the transfer, convert to local indices of mesh_out
399 do ip_out = 1, this%nrecv
400 if (.not. this%do_prolongation) then
401 this%order_out_global(ip_out) = order_out(ip_out)
402 this%order_out(ip_out) = mesh_global2local(mesh_out, order_out(ip_out))
403 else
404 ! store the global index of mesh_in
405 this%order_out_global(ip_out) = order_out_original(ip_out)
406 this%order_out(ip_out) = 0
407 end if
408 if (.not. this%do_prolongation) then
409 if (this%order_out(ip_out) == 0) then
410 write(message(1),'(a,i10,a,i10)') "Error in regridding part 2: mesh point ", &
411 this%order_out(ip_out), " is not stored in partition ", mesh_out%pv%partno
412 call messages_fatal(1, namespace=namespace)
413 end if
414 end if
415 end do
416
417 ! remove rotations for affine coordinates because they can lead to singularities in the
418 ! computation of the weights; the weights are independent of rotations
419 ! remove the rotation for the coarse mesh and use the same rotation matrix for the fine mesh
420 select type(coord_system => mesh_coarse%coord_system)
421 class is (affine_coordinates_t)
422 scaling = lalg_remove_rotation(this%dim, coord_system%basis%vectors)
423 coarse_coord => affine_coordinates_t(namespace, this%dim, scaling)
424 ! get rotation matrix from polar decomposition A = U P -> U = A P^{-1}
425 call lalg_inverse(this%dim, scaling, "dir")
426 rotation = matmul(coord_system%basis%vectors, scaling)
427 class default
428 coarse_coord => mesh_coarse%coord_system
429 rotation = diagonal_matrix(this%dim, m_one)
430 end select
431 select type(coord_system => mesh_fine%coord_system)
432 class is (affine_coordinates_t)
433 ! here we compute the new basis as U^T A
434 fine_coord => affine_coordinates_t(namespace, this%dim, &
435 matmul(transpose(rotation), coord_system%basis%vectors))
436 class default
437 fine_coord => mesh_fine%coord_system
438 end select
439 ! create transfer stencil
440 if (.not. this%generic_interpolation) then
441 if (this%do_restriction .or. this%do_prolongation) then
442 ! determine weights by requiring a set of polynomials to be exactly reproduced
443 ! on the corners of the polyhedron generated by neighbouring grid points
444 call get_transfer_stencil(this%transfer_stencil, this%dim, this%eta(1), this%interpolation_level)
445 safe_allocate(this%weights(1:this%transfer_stencil%size))
446 ! get M matrix
447 cube_size = 1+this%interpolation_level
448 safe_allocate(m(1:cube_size**this%dim, 1:cube_size**this%dim))
449 safe_allocate(p(1:cube_size**this%dim))
450 do ii = 1, cube_size**this%dim
451 ! get index of coarse point in the surrounding parallelepiped
452 ! using the corresponding index as number in base cube_size
453 call convert_to_base(ii-1, cube_size, shift)
454 x_primitive = (shift - (this%interpolation_level-1)/2)*mesh_coarse%spacing
455 x_coarse = coarse_coord%to_cartesian(x_primitive)
456 ! fill one row of M with the polynomials
457 m(ii, :) = evaluate_polynomials(x_coarse)
458 end do
459 call lalg_inverse(cube_size**this%dim, m, "dir")
460 do ii = 1, this%transfer_stencil%size
461 ! Cartesian coordinates of point in fine mesh
462 shift = -floor(real(this%transfer_stencil%points(:, ii), real64)/real(this%eta, real64))
463 x_fine = real(this%transfer_stencil%points(:, ii), real64) + shift*this%eta
464 x_fine = fine_coord%to_cartesian(x_fine * mesh_fine%spacing)
465 ! get polynomials
466 p = evaluate_polynomials(x_fine)
467 ! determine coefficients for interpolation
468 p = matmul(p, m)
469 ! take the coefficient for the correct coarse point
470 call convert_from_base(shift+(this%interpolation_level-1)/2, cube_size, i_coarse)
471 i_coarse = i_coarse + 1
472 this%weights(ii) = p(i_coarse)
473 end do
474 ! for the restriction, we need to take into account the ratio of volume elements
475 ! like this, restriction is adjoint to prolongation
476 if (this%do_restriction) then
477 this%weights(:) = this%weights(:) * mesh_fine%volume_element/mesh_coarse%volume_element
478 end if
479 safe_deallocate_a(m)
480 safe_deallocate_a(p)
481 end if
482 else
483 ! compute interpolation weights for each point
484 ! we always need at least a cube of size 2
485 cube_size = 1+max(this%interpolation_level, 1)
486 safe_allocate(this%weights_generic(1:cube_size**this%dim, 1:mesh_out%np))
487 this%weights_generic = m_zero
488 safe_allocate(this%stencil_points(1:cube_size**this%dim, 1:mesh_out%np))
489 this%stencil_points = -1
490
491 call lihash_init(global_indices)
492 ! create hash map for the global indices of the input mesh
493 do ip_out = 1, this%nrecv
494 ! it is called ip_out because it is the output of the partition_transfer
495 call lihash_insert(global_indices, this%order_out_global(ip_out), ip_out)
496 end do
497
498 safe_allocate(m(1:cube_size**this%dim, 1:cube_size**this%dim))
499 safe_allocate(p(1:cube_size**this%dim))
500 do ip_out = 1, mesh_out%np
501 call mesh_local_index_to_coords(mesh_out, ip_out, index)
502 x_out = fine_coord%to_cartesian(real(index, real64)*mesh_out%spacing)
503 x_in = coarse_coord%from_cartesian(x_out)/mesh_in%spacing
504 on_in_grid = all(abs((x_in - nint(x_in))) < 10.0_real64*m_epsilon)
505 if (on_in_grid) then
506 ! the points coincide, so use only one point in the stencil with a weight of 1
507 ipg_in = mesh_global_index_from_coords(mesh_in, nint(x_in))
508 this%stencil_points(1, ip_out) = lihash_lookup(global_indices, ipg_in, found)
509 this%weights_generic(1, ip_out) = m_one
510 else
511 ! now get all in points that surround the out point
512 ! start always from the same corner of the cube
513 ! need a cube of size of the interpolation level, so shift to the corner of that cube
514 index(:) = floor(x_in) - (max(this%interpolation_level, 1)-1)/2
515 rmin = m_huge
516 ip_mindist = -1
517 do is = 1, cube_size**this%dim
518 ! get index of coarse point in the surrounding parallelepiped
519 ! using the corresponding index as number in base cube_size
520 call convert_to_base(is-1, cube_size, shift)
521 index_stencil(:) = index(:) + shift(:)
522 ipg_in = mesh_global_index_from_coords(mesh_in, index_stencil)
523 ! the lookup will return -1 for points that are not locally available in the input mesh
524 ! those will be ignored during the regridding
525 ! the points we need from other processes are already in this hash table
526 this%stencil_points(is, ip_out) = lihash_lookup(global_indices, ipg_in, found)
527 x_in = coarse_coord%to_cartesian(index_stencil*mesh_in%spacing)
528 ! compute M
529 ! fill one row of M with the polynomials
530 m(is, :) = evaluate_polynomials(x_in)
531 ! determine closest point for nearest neighbor interpolation
532 r_current = norm2(x_in - x_out)
533 ! avoid rounding errors by requesting the distance to be smaller
534 ! by a certain amount
535 if (r_current < rmin - 10.*m_epsilon .and. found) then
536 rmin = r_current
537 ip_mindist = this%stencil_points(is, ip_out)
538 end if
539 end do
540 if (this%interpolation_level == nearest_neighbor) then
541 ! only use one point for th nearest-neighbor interpolation
542 this%weights_generic(1, ip_out) = m_one
543 this%stencil_points(:, ip_out) = -1
544 this%stencil_points(1, ip_out) = ip_mindist
545 else
546 call lalg_inverse(cube_size**this%dim, m, "dir")
547 ! get polynomials at point to be interpolated
548 p = evaluate_polynomials(x_out)
549 ! determine coefficients for interpolation
550 this%weights_generic(:, ip_out) = matmul(p, m)
551 end if
552 end if
553 end do
554 safe_deallocate_a(m)
555 safe_deallocate_a(p)
556 call lihash_end(global_indices)
557 end if
558
559 select case (this%scale_norms)
560 case(scale_none)
561 ! do nothing
562 case(scale_norm2)
563 ! create overlap map
564 safe_allocate(this%overlap_map(1:this%mesh_in%np))
565 this%overlap_map = this%mesh_out%box%contains_points(this%mesh_in%np, this%mesh_in%x_t)
566 end select
567
568 safe_deallocate_a(partition_in)
569 safe_deallocate_a(global_indices_in)
570 safe_deallocate_a(order_in)
571 safe_deallocate_a(order_out)
572
573 ! deallocate coordinate systems correctly
574 select type(coord_system => mesh_coarse%coord_system)
575 class is (affine_coordinates_t)
576 safe_deallocate_p(coarse_coord)
577 class default
578 nullify(coarse_coord)
579 end select
580 select type(coord_system => mesh_fine%coord_system)
581 class is (affine_coordinates_t)
582 safe_deallocate_p(fine_coord)
583 class default
584 nullify(fine_coord)
585 end select
586
587 pop_sub_with_profile(regridding_init)
588 contains
589 subroutine insert_global_point(mesh, ipg, ii)
590 class(mesh_t), intent(in) :: mesh
591 integer(int64), intent(in) :: ipg
592 integer, intent(inout) :: ii
593
594 integer :: ip_tmp
595 integer(int64) :: ipg_tmp
596
597 ! take boundary into account for periodic meshes
598 if ((ipg > 0 .and. ipg <= mesh%np_global) .or. &
599 (ipg > 0 .and. space_in%is_periodic())) then
600 ip_tmp = lihash_lookup(global_indices, ipg, found)
601 if (.not. found) then
602 if (ipg > mesh%np_global) then
603 ipg_tmp = mesh_periodic_point_global(mesh, space_in, ipg)
604 ! early exit if periodic copy is not inside the mesh
605 ! this can happen for partly periodic systems
606 if (ipg_tmp > mesh%np_global) return
607 end if
608 ii = ii + 1
609 ! enlarge array if necessary
610 if (ii >= size_array) then
611 size_array = size_array * 2
612 call make_array_larger(global_indices_in_tmp, size_array)
613 call make_array_larger(global_indices_in_original, size_array)
614 end if
615 if (ipg <= mesh%np_global) then
616 global_indices_in_tmp(ii) = ipg
617 global_indices_in_original(ii) = ipg
618 else if (ipg > mesh%np_global) then
619 ! save the index of the corresponding inner point
620 global_indices_in_tmp(ii) = ipg_tmp
621 global_indices_in_original(ii) = ipg
622 end if
623 call lihash_insert(global_indices, ipg, ii)
624 end if
625 end if
626 end subroutine insert_global_point
627
628 function evaluate_polynomials(x)
629 real(real64), intent(in) :: x(1:this%dim)
630 real(real64) :: evaluate_polynomials(1:(1+this%interpolation_level)**this%dim)
631 integer :: cube_size, i, j, shift(1:this%dim)
632
634 cube_size = 1+this%interpolation_level
635 do i = 1, cube_size**this%dim
636 ! get index of coarse point in the surrounding parallelepiped
637 ! using the corresponding index as number in base cube_size
638 call convert_to_base(i-1, cube_size, shift)
639 ! evaluate polynomials with the corresponding powers
640 do j = 1, this%dim
641 evaluate_polynomials(i) = evaluate_polynomials(i) * x(j)**shift(j)
642 end do
643 end do
644 end function evaluate_polynomials
645
646 subroutine get_transfer_stencil(this, dim, eta, order)
647 type(stencil_t), intent(inout) :: this
648 integer, intent(in) :: dim
649 integer, intent(in) :: eta
650 integer, intent(in) :: order
651
652 integer :: i, offset, cube_size, shift(1:dim)
653
654 push_sub(get_transfer_stencil)
655
656 cube_size = eta*(order + 1) - 1
657 call stencil_allocate(this, dim, cube_size**dim)
658
659 offset = eta * (order/2 + 1) - 1
660 do i = 1, cube_size**dim
661 call convert_to_base(i-1, cube_size, shift)
662 this%points(:, i) = shift(:) - offset
663 end do
664
665 call stencil_init_center(this)
666
667 pop_sub(get_transfer_stencil)
668 end subroutine get_transfer_stencil
669 end function regridding_init
670
671 subroutine regridding_finalize(this)
672 type(regridding_t), intent(inout) :: this
673
674 push_sub(regridding_finalize)
675
676 call partition_transfer_end(this%partition_transfer)
677 safe_deallocate_a(this%eta)
678 safe_deallocate_a(this%order_in)
679 safe_deallocate_a(this%order_in_global)
680 safe_deallocate_a(this%order_out)
681 safe_deallocate_a(this%order_out_global)
682 safe_deallocate_a(this%weights)
683 safe_deallocate_a(this%weights_generic)
684 safe_deallocate_a(this%stencil_points)
685 select case (this%scale_norms)
686 case(scale_none)
687 ! do nothing
688 case(scale_norm2)
689 safe_deallocate_a(this%overlap_map)
690 end select
691
692 pop_sub(regridding_finalize)
693 end subroutine regridding_finalize
694
695#include "real.F90"
696#include "regridding_inc.F90"
697#include "undef.F90"
698
699#include "complex.F90"
700#include "regridding_inc.F90"
701#include "undef.F90"
702
703end module regridding_oct_m
double floor(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_huge
Definition: global.F90:218
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_epsilon
Definition: global.F90:216
real(real64), parameter, public m_one
Definition: global.F90:201
This module implements the underlying real-space grid.
Definition: grid.F90:119
This module implements a simple hash table for non-negative integer keys and integer values.
Definition: iihash.F90:127
integer function, public lihash_lookup(h, key, found)
Look up a value in the hash table h. If found is present, it indicates if key could be found in the t...
Definition: iihash.F90:336
subroutine, public lihash_insert(h, key, val)
Insert a (key, val) pair into the hash table h.
Definition: iihash.F90:310
subroutine, public lihash_end(h)
Free a hash table.
Definition: iihash.F90:288
subroutine, public lihash_init(h)
Initialize a hash table h.
Definition: iihash.F90:265
real(real64) function, dimension(1:n, 1:n), public lalg_remove_rotation(n, A)
Remove rotation from affine transformation A by computing the polar decomposition and discarding the ...
Definition: lalg_adv.F90:521
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
subroutine, public convert_to_base(num, base, converted)
convert an integer in base 10 to a different base
Definition: math.F90:1503
subroutine, public convert_from_base(converted, base, num)
convert an integer to base 10 from a different base
Definition: math.F90:1529
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public mesh_global_index_to_coords(mesh, ipg, ix)
Given a global point index, this function returns the set of integer coordinates of the point.
Definition: mesh.F90:937
integer(int64) function, public mesh_global_index_from_coords(mesh, ix)
This function returns the true global index of the point for a given vector of integer coordinates.
Definition: mesh.F90:928
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:959
integer(int64) function, public mesh_periodic_point_global(mesh, space, ipg_in)
Definition: mesh.F90:767
integer function, public mesh_global2local(mesh, ipg)
This function returns the local mesh index for a given global index.
Definition: mesh.F90:981
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public partition_transfer_init(this, np, global_index, mpi_grp_in, mpi_grp_out, part_out, nsend, nrec, order_in, order_out, inverse)
initialize the partition transfer object
subroutine, public partition_transfer_end(this)
Implementation details for regridding.
Definition: regridding.F90:172
class(regridding_t) function, pointer regridding_init(mesh_out, mesh_in, space_in, namespace)
Generate a re-mapping of points from mesh_in to mesh_out.
Definition: regridding.F90:238
subroutine regridding_finalize(this)
Definition: regridding.F90:767
integer, parameter scale_norm2
Definition: regridding.F90:227
integer, parameter scale_none
Definition: regridding.F90:227
integer, parameter linear
Definition: regridding.F90:227
This module defines stencils used in Octopus.
Definition: stencil.F90:137
subroutine, public stencil_allocate(this, dim, size)
Definition: stencil.F90:181
subroutine, public stencil_init_center(this)
set the index of the central point of the stencil
Definition: stencil.F90:282
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:120
subroutine, public make_array_larger(array, new_size)
Definition: utils.F90:680
real(real64) function, dimension(1:(1+this%interpolation_level) **this%dim) evaluate_polynomials(x)
Definition: regridding.F90:724
subroutine get_transfer_stencil(this, dim, eta, order)
Definition: regridding.F90:742
subroutine insert_global_point(mesh, ipg, ii)
Definition: regridding.F90:685
Describes mesh distribution to nodes.
Definition: mesh.F90:188
contains the information of the meshes and provides the transfer functions
Definition: regridding.F90:198
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:165
int true(void)