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))
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 this%do_prolongation = .true.
245 this%do_restriction = .false.
246 this%scale_norms = scale_none
247 end if
248
249 this%mesh_in => mesh_in
250 this%mesh_out => mesh_out
251 if (.not. this%do_prolongation) then
252 mesh_fine => this%mesh_in
253 mesh_coarse => this%mesh_out
254 else
255 mesh_coarse => this%mesh_in
256 mesh_fine => this%mesh_out
257 end if
258
259 ! collect all locally available points in mesh_coarse that are also in mesh_fine
260 call lihash_init(global_indices)
261 size_array = mesh_fine%np
262 safe_allocate(global_indices_in_tmp(size_array))
263 safe_allocate(global_indices_in_original(size_array))
264
265 if (.not. this%generic_interpolation) then
266 ii = 0
267 do ip_fine = 1, mesh_fine%np
268 call mesh_local_index_to_coords(mesh_fine, ip_fine, index)
269 on_coarse_grid = .true.
270 if (this%do_restriction .or. this%do_prolongation) then
271 do idim = 1, this%dim
272 on_coarse_grid = on_coarse_grid .and. mod(index(idim), this%eta(idim)) == 0
273 end do
274 end if
275 if (on_coarse_grid) then
276 ! translate between fine and coarse grid
277 index(:) = index(:) / this%eta(:)
278 ipg_coarse = mesh_global_index_from_coords(mesh_coarse, index)
279 call insert_global_point(mesh_coarse, ipg_coarse, ii)
280 else if (this%do_restriction .or. this%do_prolongation) then
281 ! now get all coarse points that surround the fine point
282 ! start always from the same corner of the cube
283 ! need a cube of size of the interpolation level, so shift to the corner of that cube
284 index(:) = floor(real(index(:)) / this%eta(:)) - (this%interpolation_level-1)/2
285 cube_size = 1+this%interpolation_level
286 do is = 1, cube_size**this%dim
287 ! get index of coarse point in the surrounding parallelepiped
288 ! using the corresponding index as number in base cube_size
289 call convert_to_base(is-1, cube_size, shift)
290 index_stencil(:) = index(:) + shift(:)
291 ipg_coarse = mesh_global_index_from_coords(mesh_coarse, index_stencil)
292 call insert_global_point(mesh_coarse, ipg_coarse, ii)
293 end do
294 end if
295 end do
296 call lihash_end(global_indices)
297 else
298 ii = 0
299 do ip_out = 1, mesh_out%np
300 call mesh_local_index_to_coords(mesh_out, ip_out, index)
301 x_out = mesh_out%coord_system%to_cartesian(real(index, real64)*mesh_out%spacing)
302 x_in = mesh_in%coord_system%from_cartesian(x_out)/mesh_in%spacing
303 on_in_grid = all(abs((x_in - nint(x_in))) < 10.0_real64*m_epsilon)
304 if (on_in_grid) then
305 ! translate between out and in grid
306 ipg_in = mesh_global_index_from_coords(mesh_in, nint(x_in))
307 call insert_global_point(mesh_in, ipg_in, ii)
308 else
309 ! now get all points in the input mesh that surround the point in the output mesh
310 ! start always from the same corner of the cube
311 ! need a cube of size of the interpolation level, so shift to the corner of that cube
312 index(:) = floor(x_in) - (max(this%interpolation_level, 1)-1)/2
313 cube_size = 1+max(this%interpolation_level, 1)
314 do is = 1, cube_size**this%dim
315 ! get index of coarse point in the surrounding parallelepiped
316 ! using the corresponding index as number in base cube_size
317 call convert_to_base(is-1, cube_size, shift)
318 index_stencil(:) = index(:) + shift(:)
319 ipg_in = mesh_global_index_from_coords(mesh_in, index_stencil)
320 call insert_global_point(mesh_in, ipg_in, ii)
321 end do
322 end if
323 end do
324 call lihash_end(global_indices)
325 end if
326
327 safe_allocate(global_indices_in(ii))
328 safe_allocate(partition_in(ii))
329 global_indices_in(1:ii) = global_indices_in_tmp(1:ii)
330 safe_deallocate_a(global_indices_in_tmp)
331
332 if (mesh_coarse%parallel_in_domains) then
333 ! determine where the points of the coarse mesh are stored
334 call partition_get_partition_number(mesh_coarse%partition, ii, global_indices_in, partition_in)
335 else
336 partition_in = 1
337 end if
338
339 ! Init partition transfer
340 ! need inverse direction for prolongations
341 call partition_transfer_init(this%partition_transfer, ii, global_indices_in, &
342 mesh_in%mpi_grp, mesh_out%mpi_grp, partition_in, &
343 this%nsend, this%nrecv, order_in, order_out, inverse=this%do_prolongation)
344
345 ! we need to transfer the global indices of the boundary point and the corresponding
346 ! inner point for periodic meshes
347 if (space_in%is_periodic()) then
348 global_indices_in(1:ii) = global_indices_in_original(1:ii)
349 call partition_transfer_init(this%partition_transfer, ii, global_indices_in, &
350 mesh_in%mpi_grp, mesh_out%mpi_grp, partition_in, &
351 this%nsend, this%nrecv, order_in_original, order_out_original, inverse=this%do_prolongation)
352 else
353 order_in_original = order_in
354 order_out_original = order_out
355 end if
356
357 ! convert from global to local indices
358 safe_allocate(this%order_in(1:this%nsend))
359 safe_allocate(this%order_in_global(1:this%nsend))
360 safe_allocate(this%order_out(1:this%nrecv))
361 safe_allocate(this%order_out_global(1:this%nrecv))
362
363 ! get the mapping for mesh_in in the order given by the global indices of mesh_out
364 do ip_in = 1, this%nsend
365 if (this%do_restriction) then
366 ! in this case, we have an index on mesh_out
367 this%order_in_global(ip_in) = order_in_original(ip_in)
368 this%order_in(ip_in) = 0
369 else if (this%do_prolongation) then
370 ! in this case, we have an index on mesh_in
371 this%order_in_global(ip_in) = order_in(ip_in)
372 this%order_in(ip_in) = mesh_global2local(mesh_in, this%order_in_global(ip_in))
373 else
374 ! convert back from the global index of mesh_out to a local index of mesh_in
375 call mesh_global_index_to_coords(mesh_out, order_in_original(ip_in), index)
376 this%order_in_global(ip_in) = mesh_global_index_from_coords(mesh_in, index)
377 this%order_in(ip_in) = mesh_global2local(mesh_in, this%order_in_global(ip_in))
378 end if
379 if (.not. this%do_restriction) then
380 if (this%order_in(ip_in) == 0) then
381 write(message(1),'(a,i10,a,i10)') "Error in regridding part 1: mesh point ", &
382 this%order_in(ip_in), " is not stored in partition ", mesh_in%pv%partno
383 call messages_fatal(1, namespace=namespace)
384 end if
385 end if
386 end do
387
388 ! for mapping back to the global grid after the transfer, convert to local indices of mesh_out
389 do ip_out = 1, this%nrecv
390 if (.not. this%do_prolongation) then
391 this%order_out_global(ip_out) = order_out(ip_out)
392 this%order_out(ip_out) = mesh_global2local(mesh_out, order_out(ip_out))
393 else
394 ! store the global index of mesh_in
395 this%order_out_global(ip_out) = order_out_original(ip_out)
396 this%order_out(ip_out) = 0
397 end if
398 if (.not. this%do_prolongation) then
399 if (this%order_out(ip_out) == 0) then
400 write(message(1),'(a,i10,a,i10)') "Error in regridding part 2: mesh point ", &
401 this%order_out(ip_out), " is not stored in partition ", mesh_out%pv%partno
402 call messages_fatal(1, namespace=namespace)
403 end if
404 end if
405 end do
406
407 ! remove rotations for affine coordinates because they can lead to singularities in the
408 ! computation of the weights; the weights are independent of rotations
409 ! remove the rotation for the coarse mesh and use the same rotation matrix for the fine mesh
410 select type(coord_system => mesh_coarse%coord_system)
411 class is (affine_coordinates_t)
412 scaling = lalg_remove_rotation(this%dim, coord_system%basis%vectors)
413 coarse_coord => affine_coordinates_t(namespace, this%dim, scaling)
414 ! get rotation matrix from polar decomposition A = U P -> U = A P^{-1}
415 call lalg_inverse(this%dim, scaling, "dir")
416 rotation = matmul(coord_system%basis%vectors, scaling)
417 class default
418 coarse_coord => mesh_coarse%coord_system
419 rotation = diagonal_matrix(this%dim, m_one)
420 end select
421 select type(coord_system => mesh_fine%coord_system)
422 class is (affine_coordinates_t)
423 ! here we compute the new basis as U^T A
424 fine_coord => affine_coordinates_t(namespace, this%dim, &
425 matmul(transpose(rotation), coord_system%basis%vectors))
426 class default
427 fine_coord => mesh_fine%coord_system
428 end select
429 ! create transfer stencil
430 if (.not. this%generic_interpolation) then
431 if (this%do_restriction .or. this%do_prolongation) then
432 ! determine weights by requiring a set of polynomials to be exactly reproduced
433 ! on the corners of the polyhedron generated by neighbouring grid points
434 call get_transfer_stencil(this%transfer_stencil, this%dim, this%eta(1), this%interpolation_level)
435 safe_allocate(this%weights(1:this%transfer_stencil%size))
436 ! get M matrix
437 cube_size = 1+this%interpolation_level
438 safe_allocate(m(1:cube_size**this%dim, 1:cube_size**this%dim))
439 safe_allocate(p(1:cube_size**this%dim))
440 do ii = 1, cube_size**this%dim
441 ! get index of coarse point in the surrounding parallelepiped
442 ! using the corresponding index as number in base cube_size
443 call convert_to_base(ii-1, cube_size, shift)
444 x_primitive = (shift - (this%interpolation_level-1)/2)*mesh_coarse%spacing
445 x_coarse = coarse_coord%to_cartesian(x_primitive)
446 ! fill one row of M with the polynomials
447 m(ii, :) = evaluate_polynomials(x_coarse)
448 end do
449 call lalg_inverse(cube_size**this%dim, m, "dir")
450 do ii = 1, this%transfer_stencil%size
451 ! Cartesian coordinates of point in fine mesh
452 shift = -floor(real(this%transfer_stencil%points(:, ii), real64)/real(this%eta, real64))
453 x_fine = real(this%transfer_stencil%points(:, ii), real64) + shift*this%eta
454 x_fine = fine_coord%to_cartesian(x_fine * mesh_fine%spacing)
455 ! get polynomials
456 p = evaluate_polynomials(x_fine)
457 ! determine coefficients for interpolation
458 p = matmul(p, m)
459 ! take the coefficient for the correct coarse point
460 call convert_from_base(shift+(this%interpolation_level-1)/2, cube_size, i_coarse)
461 i_coarse = i_coarse + 1
462 this%weights(ii) = p(i_coarse)
463 end do
464 ! for the restriction, we need to take into account the ratio of volume elements
465 ! like this, restriction is adjoint to prolongation
466 if (this%do_restriction) then
467 this%weights(:) = this%weights(:) * mesh_fine%volume_element/mesh_coarse%volume_element
468 end if
469 safe_deallocate_a(m)
470 safe_deallocate_a(p)
471 end if
472 else
473 ! compute interpolation weights for each point
474 ! we always need at least a cube of size 2
475 cube_size = 1+max(this%interpolation_level, 1)
476 safe_allocate(this%weights_generic(1:cube_size**this%dim, 1:mesh_out%np))
477 this%weights_generic = m_zero
478 safe_allocate(this%stencil_points(1:cube_size**this%dim, 1:mesh_out%np))
479 this%stencil_points = -1
480
481 call lihash_init(global_indices)
482 ! create hash map for the global indices of the input mesh
483 do ip_out = 1, this%nrecv
484 ! it is called ip_out because it is the output of the partition_transfer
485 call lihash_insert(global_indices, this%order_out_global(ip_out), ip_out)
486 end do
487
488 safe_allocate(m(1:cube_size**this%dim, 1:cube_size**this%dim))
489 safe_allocate(p(1:cube_size**this%dim))
490 do ip_out = 1, mesh_out%np
491 call mesh_local_index_to_coords(mesh_out, ip_out, index)
492 x_out = fine_coord%to_cartesian(real(index, real64)*mesh_out%spacing)
493 x_in = coarse_coord%from_cartesian(x_out)/mesh_in%spacing
494 on_in_grid = all(abs((x_in - nint(x_in))) < 10.0_real64*m_epsilon)
495 if (on_in_grid) then
496 ! the points coincide, so use only one point in the stencil with a weight of 1
497 ipg_in = mesh_global_index_from_coords(mesh_in, nint(x_in))
498 this%stencil_points(1, ip_out) = lihash_lookup(global_indices, ipg_in, found)
499 this%weights_generic(1, ip_out) = m_one
500 else
501 ! now get all in points that surround the out point
502 ! start always from the same corner of the cube
503 ! need a cube of size of the interpolation level, so shift to the corner of that cube
504 index(:) = floor(x_in) - (max(this%interpolation_level, 1)-1)/2
505 rmin = m_huge
506 ip_mindist = -1
507 do is = 1, cube_size**this%dim
508 ! get index of coarse point in the surrounding parallelepiped
509 ! using the corresponding index as number in base cube_size
510 call convert_to_base(is-1, cube_size, shift)
511 index_stencil(:) = index(:) + shift(:)
512 ipg_in = mesh_global_index_from_coords(mesh_in, index_stencil)
513 ! the lookup will return -1 for points that are not locally available in the input mesh
514 ! those will be ignored during the regridding
515 ! the points we need from other processes are already in this hash table
516 this%stencil_points(is, ip_out) = lihash_lookup(global_indices, ipg_in, found)
517 x_in = coarse_coord%to_cartesian(index_stencil*mesh_in%spacing)
518 ! compute M
519 ! fill one row of M with the polynomials
520 m(is, :) = evaluate_polynomials(x_in)
521 ! determine closest point for nearest neighbor interpolation
522 r_current = norm2(x_in - x_out)
523 ! avoid rounding errors by requesting the distance to be smaller
524 ! by a certain amount
525 if (r_current < rmin - 10.*m_epsilon .and. found) then
526 rmin = r_current
527 ip_mindist = this%stencil_points(is, ip_out)
528 end if
529 end do
530 if (this%interpolation_level == nearest_neighbor) then
531 ! only use one point for th nearest-neighbor interpolation
532 this%weights_generic(1, ip_out) = m_one
533 this%stencil_points(:, ip_out) = -1
534 this%stencil_points(1, ip_out) = ip_mindist
535 else
536 call lalg_inverse(cube_size**this%dim, m, "dir")
537 ! get polynomials at point to be interpolated
538 p = evaluate_polynomials(x_out)
539 ! determine coefficients for interpolation
540 this%weights_generic(:, ip_out) = matmul(p, m)
541 end if
542 end if
543 end do
544 safe_deallocate_a(m)
545 safe_deallocate_a(p)
546 call lihash_end(global_indices)
547 end if
548
549 select case (this%scale_norms)
550 case(scale_none)
551 ! do nothing
552 case(scale_norm2)
553 ! create overlap map
554 safe_allocate(this%overlap_map(1:this%mesh_in%np))
555 this%overlap_map = this%mesh_out%box%contains_points(this%mesh_in%np, this%mesh_in%x)
556 end select
557
558 safe_deallocate_a(partition_in)
559 safe_deallocate_a(global_indices_in)
560 safe_deallocate_a(order_in)
561 safe_deallocate_a(order_out)
562
563 ! deallocate coordinate systems correctly
564 select type(coord_system => mesh_coarse%coord_system)
565 class is (affine_coordinates_t)
566 safe_deallocate_p(coarse_coord)
567 class default
568 nullify(coarse_coord)
569 end select
570 select type(coord_system => mesh_fine%coord_system)
571 class is (affine_coordinates_t)
572 safe_deallocate_p(fine_coord)
573 class default
574 nullify(fine_coord)
575 end select
576
577 pop_sub_with_profile(regridding_init)
578 contains
579 subroutine insert_global_point(mesh, ipg, ii)
580 class(mesh_t), intent(in) :: mesh
581 integer(int64), intent(in) :: ipg
582 integer, intent(inout) :: ii
583
584 integer :: ip_tmp
585
586 ! take boundary into account for periodic meshes
587 if (ipg > 0 .and. ipg <= mesh%np_global .or. &
588 ipg > 0 .and. space_in%is_periodic()) then
589 ip_tmp = lihash_lookup(global_indices, ipg, found)
590 if (.not. found) then
591 ii = ii + 1
592 ! enlarge array if necessary
593 if (ii >= size_array) then
594 size_array = size_array * 2
595 call make_array_larger(global_indices_in_tmp, size_array)
596 call make_array_larger(global_indices_in_original, size_array)
597 end if
598 if (ipg <= mesh%np_global) then
599 global_indices_in_tmp(ii) = ipg
600 global_indices_in_original(ii) = ipg
601 else if (ipg > mesh%np_global) then
602 global_indices_in_tmp(ii) = mesh_periodic_point_global(mesh, space_in, ipg)
603 global_indices_in_original(ii) = ipg
604 end if
605 call lihash_insert(global_indices, ipg, ii)
606 end if
607 end if
608 end subroutine insert_global_point
609
610 function evaluate_polynomials(x)
611 real(real64), intent(in) :: x(1:this%dim)
612 real(real64) :: evaluate_polynomials(1:(1+this%interpolation_level)**this%dim)
613 integer :: cube_size, i, j, shift(1:this%dim)
614
616 cube_size = 1+this%interpolation_level
617 do i = 1, cube_size**this%dim
618 ! get index of coarse point in the surrounding parallelepiped
619 ! using the corresponding index as number in base cube_size
620 call convert_to_base(i-1, cube_size, shift)
621 ! evaluate polynomials with the corresponding powers
622 do j = 1, this%dim
623 evaluate_polynomials(i) = evaluate_polynomials(i) * x(j)**shift(j)
624 end do
625 end do
626 end function evaluate_polynomials
627
628 subroutine get_transfer_stencil(this, dim, eta, order)
629 type(stencil_t), intent(inout) :: this
630 integer, intent(in) :: dim
631 integer, intent(in) :: eta
632 integer, intent(in) :: order
633
634 integer :: i, offset, cube_size, shift(1:dim)
635
636 push_sub(get_transfer_stencil)
637
638 cube_size = eta*(order + 1) - 1
639 call stencil_allocate(this, dim, cube_size**dim)
640
641 offset = eta * (order/2 + 1) - 1
642 do i = 1, cube_size**dim
643 call convert_to_base(i-1, cube_size, shift)
644 this%points(:, i) = shift(:) - offset
645 end do
646
647 call stencil_init_center(this)
648
649 pop_sub(get_transfer_stencil)
650 end subroutine get_transfer_stencil
651 end function regridding_init
652
653 subroutine regridding_finalize(this)
654 type(regridding_t), intent(inout) :: this
655
656 push_sub(regridding_finalize)
657
658 call partition_transfer_end(this%partition_transfer)
659 safe_deallocate_a(this%eta)
660 safe_deallocate_a(this%order_in)
661 safe_deallocate_a(this%order_in_global)
662 safe_deallocate_a(this%order_out)
663 safe_deallocate_a(this%order_out_global)
664 safe_deallocate_a(this%weights)
665 select case (this%scale_norms)
666 case(scale_none)
667 ! do nothing
668 case(scale_norm2)
669 safe_deallocate_a(this%overlap_map)
670 end select
671
673 end subroutine regridding_finalize
674
675#include "real.F90"
676#include "regridding_inc.F90"
677#include "undef.F90"
678
679#include "complex.F90"
680#include "regridding_inc.F90"
681#include "undef.F90"
682
683end module regridding_oct_m
double floor(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_huge
Definition: global.F90:206
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_epsilon
Definition: global.F90:204
real(real64), parameter, public m_one
Definition: global.F90:189
This module implements the underlying real-space grid.
Definition: grid.F90:117
This module implements a simple hash table for non-negative integer keys and integer values.
Definition: iihash.F90:125
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:334
subroutine, public lihash_insert(h, key, val)
Insert a (key, val) pair into the hash table h.
Definition: iihash.F90:308
subroutine, public lihash_end(h)
Free a hash table.
Definition: iihash.F90:286
subroutine, public lihash_init(h)
Initialize a hash table h.
Definition: iihash.F90:263
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:738
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
subroutine, public convert_to_base(num, base, converted)
convert an integer in base 10 to a different base
Definition: math.F90:1499
subroutine, public convert_from_base(converted, base, num)
convert an integer to base 10 from a different base
Definition: math.F90:1525
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 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:925
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:916
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
integer(int64) function, public mesh_periodic_point_global(mesh, space, ipg_in)
Definition: mesh.F90:746
integer function, public mesh_global2local(mesh, ipg)
This function returns the local mesh index for a given global index.
Definition: mesh.F90:969
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:414
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:170
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:236
subroutine regridding_finalize(this)
Definition: regridding.F90:747
integer, parameter scale_norm2
Definition: regridding.F90:225
integer, parameter scale_none
Definition: regridding.F90:225
integer, parameter linear
Definition: regridding.F90:225
This module defines stencils used in Octopus.
Definition: stencil.F90:135
subroutine, public stencil_allocate(this, dim, size)
Definition: stencil.F90:178
subroutine, public stencil_init_center(this)
Definition: stencil.F90:275
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:118
subroutine, public make_array_larger(array, new_size)
Definition: utils.F90:629
real(real64) function, dimension(1:(1+this%interpolation_level) **this%dim) evaluate_polynomials(x)
Definition: regridding.F90:704
subroutine get_transfer_stencil(this, dim, eta, order)
Definition: regridding.F90:722
subroutine insert_global_point(mesh, ipg, ii)
Definition: regridding.F90:673
Describes mesh distribution to nodes.
Definition: mesh.F90:186
contains the information of the meshes and provides the transfer functions
Definition: regridding.F90:196
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:163
int true(void)