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
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
129 procedure regridding_init
132 integer,
parameter :: &
133 NEAREST_NEIGHBOR = 0, &
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
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
172 nullify(coarse_coord)
188 call parse_variable(namespace,
"RegriddingInterpolationLevel",
linear, this%interpolation_level)
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."
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)
222 if (this%do_prolongation) spacing_ratio =
m_one/spacing_ratio
224 safe_allocate(this%eta(1:this%dim))
225 do idim = 1, this%dim
226 this%eta(idim) = nint(spacing_ratio(idim))
228 if (any(abs((spacing_ratio - this%eta)/spacing_ratio) > 10.0_real64*
m_epsilon))
then
229 this%generic_interpolation = .
true.
232 do idim = 2, this%dim
233 same_eta = same_eta .and. this%eta(idim) == this%eta(idim-1)
235 if (.not. same_eta)
then
236 this%generic_interpolation = .
true.
239 if (this%interpolation_level == nearest_neighbor)
then
240 this%generic_interpolation = .
true.
243 if (this%generic_interpolation)
then
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."
254 this%do_prolongation = .
true.
255 this%do_restriction = .false.
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
265 mesh_coarse => this%mesh_in
266 mesh_fine => this%mesh_out
271 size_array = mesh_fine%np
272 safe_allocate(global_indices_in_tmp(size_array))
273 safe_allocate(global_indices_in_original(size_array))
275 if (.not. this%generic_interpolation)
then
277 do ip_fine = 1, mesh_fine%np
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
285 if (on_coarse_grid)
then
287 index(:) = index(:) / this%eta(:)
290 else if (this%do_restriction .or. this%do_prolongation)
then
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
300 index_stencil(:) = index(:) + shift(:)
309 do ip_out = 1, mesh_out%np
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)
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
328 index_stencil(:) = index(:) + shift(:)
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)
342 if (mesh_coarse%parallel_in_domains)
then
352 mesh_in%mpi_grp, mesh_out%mpi_grp, partition_in, &
353 this%nsend, this%nrecv, order_in, order_out, inverse=this%do_prolongation)
357 if (space_in%is_periodic())
then
358 global_indices_in(1:ii) = global_indices_in_original(1:ii)
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)
363 order_in_original = order_in
364 order_out_original = order_out
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))
374 do ip_in = 1, this%nsend
375 if (this%do_restriction)
then
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
381 this%order_in_global(ip_in) = order_in(ip_in)
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
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)
405 this%order_out_global(ip_out) = order_out_original(ip_out)
406 this%order_out(ip_out) = 0
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
420 select type(coord_system => mesh_coarse%coord_system)
426 rotation = matmul(coord_system%basis%vectors, scaling)
428 coarse_coord => mesh_coarse%coord_system
431 select type(coord_system => mesh_fine%coord_system)
435 matmul(transpose(rotation), coord_system%basis%vectors))
437 fine_coord => mesh_fine%coord_system
440 if (.not. this%generic_interpolation)
then
441 if (this%do_restriction .or. this%do_prolongation)
then
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))
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
454 x_primitive = (shift - (this%interpolation_level-1)/2)*mesh_coarse%spacing
455 x_coarse = coarse_coord%to_cartesian(x_primitive)
460 do ii = 1, this%transfer_stencil%size
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)
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)
476 if (this%do_restriction)
then
477 this%weights(:) = this%weights(:) * mesh_fine%volume_element/mesh_coarse%volume_element
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
493 do ip_out = 1, this%nrecv
495 call lihash_insert(global_indices, this%order_out_global(ip_out), ip_out)
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
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)
508 this%stencil_points(1, ip_out) =
lihash_lookup(global_indices, ipg_in, found)
509 this%weights_generic(1, ip_out) =
m_one
514 index(:) =
floor(x_in) - (max(this%interpolation_level, 1)-1)/2
517 do is = 1, cube_size**this%dim
521 index_stencil(:) = index(:) + shift(:)
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)
532 r_current = norm2(x_in - x_out)
535 if (r_current < rmin - 10.*
m_epsilon .and. found)
then
537 ip_mindist = this%stencil_points(is, ip_out)
540 if (this%interpolation_level == nearest_neighbor)
then
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
550 this%weights_generic(:, ip_out) = matmul(p, m)
559 select case (this%scale_norms)
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)
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)
574 select type(coord_system => mesh_coarse%coord_system)
576 safe_deallocate_p(coarse_coord)
578 nullify(coarse_coord)
580 select type(coord_system => mesh_fine%coord_system)
582 safe_deallocate_p(fine_coord)
590 class(
mesh_t),
intent(in) :: mesh
591 integer(int64),
intent(in) :: ipg
592 integer,
intent(inout) :: ii
595 integer(int64) :: ipg_tmp
598 if ((ipg > 0 .and. ipg <= mesh%np_global) .or. &
599 (ipg > 0 .and. space_in%is_periodic()))
then
601 if (.not. found)
then
602 if (ipg > mesh%np_global)
then
606 if (ipg_tmp > mesh%np_global)
return
610 if (ii >= size_array)
then
611 size_array = size_array * 2
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
620 global_indices_in_tmp(ii) = ipg_tmp
621 global_indices_in_original(ii) = ipg
629 real(real64),
intent(in) :: x(1:this%dim)
631 integer :: cube_size, i, j, shift(1:this%dim)
634 cube_size = 1+this%interpolation_level
635 do i = 1, cube_size**this%dim
648 integer,
intent(in) :: dim
649 integer,
intent(in) :: eta
650 integer,
intent(in) :: order
652 integer :: i, offset, cube_size, shift(1:dim)
656 cube_size = eta*(order + 1) - 1
659 offset = eta * (order/2 + 1) - 1
660 do i = 1, cube_size**dim
662 this%points(:, i) = shift(:) - offset
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)
689 safe_deallocate_a(this%overlap_map)
696#include "regridding_inc.F90"
699#include "complex.F90"
700#include "regridding_inc.F90"
double floor(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_huge
real(real64), parameter, public m_zero
real(real64), parameter, public m_epsilon
real(real64), parameter, public m_one
This module implements the underlying real-space grid.
This module implements a simple hash table for non-negative integer keys and integer values.
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...
subroutine, public lihash_insert(h, key, val)
Insert a (key, val) pair into the hash table h.
subroutine, public lihash_end(h)
Free a hash table.
subroutine, public lihash_init(h)
Initialize a hash table h.
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 ...
This module is intended to contain "only mathematical" functions and procedures.
subroutine, public convert_to_base(num, base, converted)
convert an integer in base 10 to a different base
subroutine, public convert_from_base(converted, base, num)
convert an integer to base 10 from a different base
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
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.
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.
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.
integer(int64) function, public mesh_periodic_point_global(mesh, space, ipg_in)
integer function, public mesh_global2local(mesh, ipg)
This function returns the local mesh index for a given global index.
subroutine, public messages_warning(no_lines, all_nodes, namespace)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
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.
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.
subroutine regridding_finalize(this)
integer, parameter scale_norm2
integer, parameter scale_none
integer, parameter linear
This module defines stencils used in Octopus.
subroutine, public stencil_allocate(this, dim, size)
subroutine, public stencil_init_center(this)
set the index of the central point of the stencil
This module is intended to contain simple general-purpose utility functions and procedures.
subroutine, public make_array_larger(array, new_size)
real(real64) function, dimension(1:(1+this%interpolation_level) **this%dim) evaluate_polynomials(x)
subroutine get_transfer_stencil(this, dim, eta, order)
subroutine insert_global_point(mesh, ipg, ii)
Describes mesh distribution to nodes.
contains the information of the meshes and provides the transfer functions
The class representing the stencil, which is used for non-local mesh operations.