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
97 use utils_oct_m
98
99 implicit none
100 public :: regridding_t
101
104 type :: regridding_t
105 private
106 class(mesh_t), pointer :: mesh_in, mesh_out
107 type(partition_transfer_t) :: partition_transfer
108 integer :: nsend, nrecv, dim
109 integer, allocatable :: order_in(:), order_out(:)
110 integer(int64), allocatable :: order_in_global(:), order_out_global(:)
111 logical, allocatable :: overlap_map(:)
112 logical :: do_restriction, do_prolongation
113 type(stencil_t) :: transfer_stencil
114 real(real64), allocatable :: weights(:)
115 real(real64), allocatable :: weights_generic(:, :)
116 integer, allocatable :: stencil_points(:, :)
117 integer, allocatable :: eta(:)
118 integer :: interpolation_level
119 integer :: scale_norms
120 logical :: generic_interpolation
121 contains
122 procedure :: dregridding_do_transfer_1, zregridding_do_transfer_1
123 procedure :: dregridding_do_transfer_2, zregridding_do_transfer_2
124 generic :: do_transfer => dregridding_do_transfer_1, zregridding_do_transfer_1
125 generic :: do_transfer => dregridding_do_transfer_2, zregridding_do_transfer_2
126 final :: regridding_finalize
127 end type regridding_t
128
129 interface regridding_t
130 procedure regridding_init
131 end interface regridding_t
132
133 integer, parameter :: &
134 LINEAR = 0, &
135 nearest_neighbor = 1, &
136 scale_none = 0, &
137 scale_norm2 = 1
138
139contains
140
141 ! ---------------------------------------------------------
143 function regridding_init(mesh_out, mesh_in, space_in, namespace) result(this)
144 class(mesh_t), target, intent(in) :: mesh_out
145 class(mesh_t), target, intent(in) :: mesh_in
146 class(space_t), intent(in) :: space_in
147 type(namespace_t), intent(in) :: namespace
148 class(regridding_t), pointer :: this
149
150 integer :: ip_in, ip_out, index(1:space_in%dim), idim, ii, is, size_array
151 integer(int64), allocatable :: global_indices_in(:), order_in(:), order_out(:)
152 integer(int64), allocatable :: order_in_original(:), order_out_original(:)
153 integer(int64), allocatable :: global_indices_in_tmp(:)
154 integer(int64), allocatable :: global_indices_in_original(:)
155 integer, allocatable :: partition_in(:)
156 integer(int64) :: ipg_coarse, ipg_in
157 real(real64) :: spacing_ratio(1:space_in%dim)
158 real(real64) :: x_fine(1:space_in%dim), x_coarse(1:space_in%dim), x_primitive(1:space_in%dim)
159 real(real64) :: x_out(1:space_in%dim), x_in(1:space_in%dim), rmin, r_current
160 real(real64) :: M(1:2**space_in%dim, 1:2**space_in%dim), p(1:2**space_in%dim)
161 real(real64) :: scaling(1:space_in%dim, 1:space_in%dim), rotation(1:space_in%dim, 1:space_in%dim)
162 integer :: i_coarse, ip_fine, ip_mindist
163 integer :: index_stencil(1:space_in%dim), shift(1:space_in%dim)
164 logical :: same_eta, on_coarse_grid, found, on_in_grid
165 type(lihash_t) :: global_indices
166 class(mesh_t), pointer :: mesh_coarse, mesh_fine
167 class(coordinate_system_t), pointer :: coarse_coord, fine_coord
168
169 push_sub_with_profile(regridding_init)
171 safe_allocate(this)
172
173 nullify(coarse_coord)
174 nullify(fine_coord)
175
176 !%Variable RegriddingInterpolationLevel
177 !%Type integer
178 !%Default regridding_linear
179 !%Section Mesh
180 !%Description
181 !% Choose the interpolation level for the regridding.
182 !%Option regridding_linear 0
183 !% Use a trilinear interpolation. This is implemented similar to restriction and prolongation
184 !% operations in multigrid methods. This ensures that both directions are adjoint to each other.
185 !%Option regridding_nearest_neighbor 1
186 !% Use the nearest neighbor for the regridding. This is faster than the linear interpolation.
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
239 if (this%generic_interpolation) then
240 this%do_prolongation = .true.
241 this%do_restriction = .false.
242 this%scale_norms = scale_none
243 end if
244
245 this%mesh_in => mesh_in
246 this%mesh_out => mesh_out
247 if (.not. this%do_prolongation) then
248 mesh_fine => this%mesh_in
249 mesh_coarse => this%mesh_out
250 else
251 mesh_coarse => this%mesh_in
252 mesh_fine => this%mesh_out
253 end if
254
255 ! collect all locally available points in mesh_coarse that are also in mesh_fine
256 call lihash_init(global_indices)
257 size_array = mesh_fine%np
258 safe_allocate(global_indices_in_tmp(size_array))
259 safe_allocate(global_indices_in_original(size_array))
260
261 if (.not. this%generic_interpolation) then
262 ii = 0
263 do ip_fine = 1, mesh_fine%np
264 call mesh_local_index_to_coords(mesh_fine, ip_fine, index)
265 on_coarse_grid = .true.
266 if (this%do_restriction .or. this%do_prolongation) then
267 do idim = 1, this%dim
268 on_coarse_grid = on_coarse_grid .and. mod(index(idim), this%eta(idim)) == 0
269 end do
270 end if
271 if (on_coarse_grid) then
272 ! translate between fine and coarse grid
273 index(:) = index(:) / this%eta(:)
274 ipg_coarse = mesh_global_index_from_coords(mesh_coarse, index)
275 call insert_global_point(mesh_coarse, ipg_coarse, ii)
276 else if ((this%do_restriction .and. this%interpolation_level == linear) .or. this%do_prolongation) then
277 ! now get all coarse points that surround the fine point
278 ! start always from the same corner of the cube
279 index(:) = floor(real(index(:)) / this%eta(:))
280 do is = 1, 2**this%dim
281 ! get index of coarse point in the surrounding parallelepiped using bit patterns
282 ! e.g. point 3 is 011 -> ix=0, iy=1, iz=1
283 do idim = 1, this%dim
284 shift(idim) = ibits(is-1, idim-1, 1)
285 end do
286 index_stencil(:) = index(:) + shift(:)
287 ipg_coarse = mesh_global_index_from_coords(mesh_coarse, index_stencil)
288 call insert_global_point(mesh_coarse, ipg_coarse, ii)
289 end do
290 end if
291 end do
292 call lihash_end(global_indices)
293 else
294 ii = 0
295 do ip_out = 1, mesh_out%np
296 call mesh_local_index_to_coords(mesh_out, ip_out, index)
297 x_out = mesh_out%coord_system%to_cartesian(real(index, real64)*mesh_out%spacing)
298 x_in = mesh_in%coord_system%from_cartesian(x_out)/mesh_in%spacing
299 on_in_grid = all(abs((x_in - nint(x_in))) < 10.0_real64*m_epsilon)
300 if (on_in_grid) then
301 ! translate between out and in grid
302 ipg_in = mesh_global_index_from_coords(mesh_in, nint(x_in))
303 call insert_global_point(mesh_in, ipg_in, ii)
304 else
305 ! now get all points in the input mesh that surround the point in the output mesh
306 ! start always from the same corner of the cube
307 index(:) = floor(x_in)
308 do is = 1, 2**this%dim
309 ! get index of in point in the surrounding parallelepiped using bit patterns
310 ! e.g. point 3 is 011 -> ix=0, iy=1, iz=1
311 do idim = 1, this%dim
312 shift(idim) = ibits(is-1, idim-1, 1)
313 end do
314 index_stencil(:) = index(:) + shift(:)
315 ipg_in = mesh_global_index_from_coords(mesh_in, index_stencil)
316 call insert_global_point(mesh_in, ipg_in, ii)
317 end do
318 end if
319 end do
320 call lihash_end(global_indices)
321 end if
322
323 safe_allocate(global_indices_in(ii))
324 safe_allocate(partition_in(ii))
325 global_indices_in(1:ii) = global_indices_in_tmp(1:ii)
326 safe_deallocate_a(global_indices_in_tmp)
327
328 if (mesh_coarse%parallel_in_domains) then
329 ! determine where the points of the coarse mesh are stored
330 call partition_get_partition_number(mesh_coarse%partition, ii, global_indices_in, partition_in)
331 else
332 partition_in = 1
333 end if
334
335 ! Init partition transfer
336 ! need inverse direction for prolongations
337 call partition_transfer_init(this%partition_transfer, ii, global_indices_in, &
338 mesh_in%mpi_grp, mesh_out%mpi_grp, partition_in, &
339 this%nsend, this%nrecv, order_in, order_out, inverse=this%do_prolongation)
340
341 ! we need to transfer the global indices of the boundary point and the corresponding
342 ! inner point for periodic meshes
343 if (space_in%is_periodic()) then
344 global_indices_in(1:ii) = global_indices_in_original(1:ii)
345 call partition_transfer_init(this%partition_transfer, ii, global_indices_in, &
346 mesh_in%mpi_grp, mesh_out%mpi_grp, partition_in, &
347 this%nsend, this%nrecv, order_in_original, order_out_original, inverse=this%do_prolongation)
348 else
349 order_in_original = order_in
350 order_out_original = order_out
351 end if
352
353 ! convert from global to local indices
354 safe_allocate(this%order_in(1:this%nsend))
355 safe_allocate(this%order_in_global(1:this%nsend))
356 safe_allocate(this%order_out(1:this%nrecv))
357 safe_allocate(this%order_out_global(1:this%nrecv))
358
359 ! get the mapping for mesh_in in the order given by the global indices of mesh_out
360 do ip_in = 1, this%nsend
361 if (this%do_restriction) then
362 ! in this case, we have an index on mesh_out
363 this%order_in_global(ip_in) = order_in_original(ip_in)
364 this%order_in(ip_in) = 0
365 else if (this%do_prolongation) then
366 ! in this case, we have an index on mesh_in
367 this%order_in_global(ip_in) = order_in(ip_in)
368 this%order_in(ip_in) = mesh_global2local(mesh_in, this%order_in_global(ip_in))
369 else
370 ! convert back from the global index of mesh_out to a local index of mesh_in
371 call mesh_global_index_to_coords(mesh_out, order_in_original(ip_in), index)
372 this%order_in_global(ip_in) = mesh_global_index_from_coords(mesh_in, index)
373 this%order_in(ip_in) = mesh_global2local(mesh_in, this%order_in_global(ip_in))
374 end if
375 if (.not. this%do_restriction) then
376 if (this%order_in(ip_in) == 0) then
377 write(message(1),'(a,i10,a,i10)') "Error in regridding part 1: mesh point ", &
378 this%order_in(ip_in), " is not stored in partition ", mesh_in%pv%partno
379 call messages_fatal(1, namespace=namespace)
380 end if
381 end if
382 end do
383
384 ! for mapping back to the global grid after the transfer, convert to local indices of mesh_out
385 do ip_out = 1, this%nrecv
386 if (.not. this%do_prolongation) then
387 this%order_out_global(ip_out) = order_out(ip_out)
388 this%order_out(ip_out) = mesh_global2local(mesh_out, order_out(ip_out))
389 else
390 ! store the global index of mesh_in
391 this%order_out_global(ip_out) = order_out_original(ip_out)
392 this%order_out(ip_out) = 0
393 end if
394 if (.not. this%do_prolongation) then
395 if (this%order_out(ip_out) == 0) then
396 write(message(1),'(a,i10,a,i10)') "Error in regridding part 2: mesh point ", &
397 this%order_out(ip_out), " is not stored in partition ", mesh_out%pv%partno
398 call messages_fatal(1, namespace=namespace)
399 end if
400 end if
401 end do
402
403 ! remove rotations for affine coordinates because they can lead to singularities in the
404 ! computation of the weights; the weights are independent of rotations
405 ! remove the rotation for the coarse mesh and use the same rotation matrix for the fine mesh
406 select type(coord_system => mesh_coarse%coord_system)
407 class is (affine_coordinates_t)
408 scaling = lalg_remove_rotation(this%dim, coord_system%basis%vectors)
409 coarse_coord => affine_coordinates_t(namespace, this%dim, scaling)
410 ! get rotation matrix from polar decomposition A = U P -> U = A P^{-1}
411 call lalg_inverse(this%dim, scaling, "dir")
412 rotation = matmul(coord_system%basis%vectors, scaling)
413 class default
414 coarse_coord => mesh_coarse%coord_system
415 rotation = diagonal_matrix(this%dim, m_one)
416 end select
417 select type(coord_system => mesh_fine%coord_system)
418 class is (affine_coordinates_t)
419 ! here we compute the new basis as U^T A
420 fine_coord => affine_coordinates_t(namespace, this%dim, &
421 matmul(transpose(rotation), coord_system%basis%vectors))
422 class default
423 fine_coord => mesh_fine%coord_system
424 end select
425 ! create transfer stencil
426 if (.not. this%generic_interpolation) then
427 if (this%interpolation_level == linear .and. (this%do_restriction .or. this%do_prolongation)) then
428 ! determine weights by requiring a set of polynomials to be exactly reproduced
429 ! on the corners of the polyhedron generated by neighbouring grid points
430 call stencil_cube_get_lapl(this%transfer_stencil, this%dim, order=this%eta(1)-1)
431 safe_allocate(this%weights(1:this%transfer_stencil%size))
432 ! get M matrix
433 do ii = 1, 2**this%dim
434 ! get index of coarse point in the surrounding parallelepiped using bit patterns
435 ! e.g. point 3 is 011 -> ix=0, iy=1, iz=1
436 do idim = 1, this%dim
437 x_primitive(idim) = real(ibits(ii-1, idim-1, 1), real64) * mesh_coarse%spacing(idim)
438 end do
439 x_coarse = coarse_coord%to_cartesian(x_primitive)
440 ! fill one row of M with the polynomials
441 m(ii, :) = evaluate_polynomials(x_coarse)
442 end do
443 call lalg_inverse(2**this%dim, m, "dir")
444 do ii = 1, this%transfer_stencil%size
445 ! Cartesian coordinates of point in fine mesh
446 i_coarse = 0
447 do idim = 1, this%dim
448 x_fine(idim) = real(this%transfer_stencil%points(idim, ii), real64)
449 ! shift into the same parallelepiped
450 if (x_fine(idim) < m_zero) then
451 x_fine(idim) = x_fine(idim) + real(this%eta(idim), real64)
452 ! determine which coarse point on the surrounding parallelepiped to use
453 i_coarse = ibset(i_coarse, idim-1)
454 end if
455 end do
456 x_fine = fine_coord%to_cartesian(x_fine * mesh_fine%spacing)
457 ! get polynomials
458 p = evaluate_polynomials(x_fine)
459 ! determine coefficients for interpolation
460 p = matmul(p, m)
461 ! take the coefficient for the correct coarse point
462 i_coarse = i_coarse + 1
463 this%weights(ii) = p(i_coarse)
464 end do
465 ! for the restriction, we need to take into account the ratio of volume elements
466 ! like this, restriction is adjoint to prolongation
467 if (this%do_restriction) then
468 this%weights(:) = this%weights(:) * mesh_fine%volume_element/mesh_coarse%volume_element
469 end if
470 end if
471 else
472 ! compute interpolation weights for each point
473 safe_allocate(this%weights_generic(1:2**this%dim, 1:mesh_out%np))
474 this%weights_generic = m_zero
475 safe_allocate(this%stencil_points(1:2**this%dim, 1:mesh_out%np))
476 this%stencil_points = -1
477
478 call lihash_init(global_indices)
479 ! create hash map for the global indices of the input mesh
480 do ip_out = 1, this%nrecv
481 ! it is called ip_out because it is the output of the partition_transfer
482 call lihash_insert(global_indices, this%order_out_global(ip_out), ip_out)
483 end do
484
485 do ip_out = 1, mesh_out%np
486 call mesh_local_index_to_coords(mesh_out, ip_out, index)
487 x_out = fine_coord%to_cartesian(real(index, real64)*mesh_out%spacing)
488 x_in = coarse_coord%from_cartesian(x_out)/mesh_in%spacing
489 on_in_grid = all(abs((x_in - nint(x_in))) < 10.0_real64*m_epsilon)
490 if (on_in_grid) then
491 ! the points coincide, so use only one point in the stencil with a weight of 1
492 ipg_in = mesh_global_index_from_coords(mesh_in, nint(x_in))
493 this%stencil_points(1, ip_out) = lihash_lookup(global_indices, ipg_in, found)
494 this%weights_generic(1, ip_out) = m_one
495 else
496 ! now get all in points that surround the out point
497 ! start always from the same corner of the cube
498 index(:) = floor(x_in)
499 rmin = m_huge
500 ip_mindist = -1
501 do is = 1, 2**this%dim
502 ! get index of point in input mesh in the surrounding parallelepiped using bit patterns
503 ! e.g. point 3 is 011 -> ix=0, iy=1, iz=1
504 do idim = 1, this%dim
505 shift(idim) = ibits(is-1, idim-1, 1)
506 end do
507 index_stencil(:) = index(:) + shift(:)
508 ipg_in = mesh_global_index_from_coords(mesh_in, index_stencil)
509 ! the lookup will return -1 for points that are not locally available in the input mesh
510 ! those will be ignored during the regridding
511 ! the points we need from other processes are already in this hash table
512 this%stencil_points(is, ip_out) = lihash_lookup(global_indices, ipg_in, found)
513 x_in = coarse_coord%to_cartesian(index_stencil*mesh_in%spacing)
514 ! compute M
515 ! fill one row of M with the polynomials
516 m(is, :) = evaluate_polynomials(x_in)
517 ! determine closest point for nearest neighbor interpolation
518 r_current = norm2(x_in - x_out)
519 ! avoid rounding errors by requesting the distance to be smaller
520 ! by a certain amount
521 if (r_current < rmin - 10.*m_epsilon .and. found) then
522 rmin = r_current
523 ip_mindist = this%stencil_points(is, ip_out)
524 end if
525 end do
526 call lalg_inverse(2**this%dim, m, "dir")
527 ! get polynomials at point to be interpolated
528 p = evaluate_polynomials(x_out)
529 select case (this%interpolation_level)
530 case (linear)
531 ! determine coefficients for interpolation
532 this%weights_generic(:, ip_out) = matmul(p, m)
533 case (nearest_neighbor)
534 ! only use one point for th nearest-neighbor interpolation
535 this%weights_generic(1, ip_out) = m_one
536 this%stencil_points(:, ip_out) = -1
537 this%stencil_points(1, ip_out) = ip_mindist
538 case default
539 assert(.false.)
540 end select
541 end if
542 end do
543 call lihash_end(global_indices)
544 end if
545
546 select case (this%scale_norms)
547 case(scale_none)
548 ! do nothing
549 case(scale_norm2)
550 ! create overlap map
551 safe_allocate(this%overlap_map(1:this%mesh_in%np))
552 this%overlap_map = this%mesh_out%box%contains_points(this%mesh_in%np, this%mesh_in%x)
553 end select
554
555 safe_deallocate_a(partition_in)
556 safe_deallocate_a(global_indices_in)
557 safe_deallocate_a(order_in)
558 safe_deallocate_a(order_out)
559
560 ! deallocate coordinate systems correctly
561 select type(coord_system => mesh_coarse%coord_system)
562 class is (affine_coordinates_t)
563 safe_deallocate_p(coarse_coord)
564 class default
565 nullify(coarse_coord)
566 end select
567 select type(coord_system => mesh_fine%coord_system)
568 class is (affine_coordinates_t)
569 safe_deallocate_p(fine_coord)
570 class default
571 nullify(fine_coord)
572 end select
573
574 pop_sub_with_profile(regridding_init)
575 contains
576 subroutine insert_global_point(mesh, ipg, ii)
577 class(mesh_t), intent(in) :: mesh
578 integer(int64), intent(in) :: ipg
579 integer, intent(inout) :: ii
580
581 integer :: ip_tmp
582
583 ! take boundary into account for periodic meshes
584 if (ipg > 0 .and. ipg <= mesh%np_global .or. &
585 ipg > 0 .and. space_in%is_periodic()) then
586 ip_tmp = lihash_lookup(global_indices, ipg, found)
587 if (.not. found) then
588 ii = ii + 1
589 ! enlarge array if necessary
590 if (ii >= size_array) then
591 size_array = size_array * 2
592 call make_array_larger(global_indices_in_tmp, size_array)
593 call make_array_larger(global_indices_in_original, size_array)
594 end if
595 if (ipg <= mesh%np_global) then
596 global_indices_in_tmp(ii) = ipg
597 global_indices_in_original(ii) = ipg
598 else if (ipg > mesh%np_global) then
599 global_indices_in_tmp(ii) = mesh_periodic_point_global(mesh, space_in, ipg)
600 global_indices_in_original(ii) = ipg
601 end if
602 call lihash_insert(global_indices, ipg, ii)
603 end if
604 end if
605 end subroutine insert_global_point
606
607 function evaluate_polynomials(x)
608 real(real64), intent(in) :: x(1:2**this%dim)
609 real(real64) :: evaluate_polynomials(1:2**this%dim)
610
611 if (this%dim == 1) then
613 evaluate_polynomials(2) = x(1)
614 else if (this%dim == 2) then
616 evaluate_polynomials(2) = x(1)
617 evaluate_polynomials(3) = x(2)
618 evaluate_polynomials(4) = x(1) * x(2)
619 else if (this%dim == 3) then
621 evaluate_polynomials(2) = x(1)
622 evaluate_polynomials(3) = x(2)
623 evaluate_polynomials(4) = x(3)
624 evaluate_polynomials(5) = x(1) * x(2)
625 evaluate_polynomials(6) = x(1) * x(3)
626 evaluate_polynomials(7) = x(2) * x(3)
627 evaluate_polynomials(8) = x(1) * x(2) * x(3)
628 else
629 message(1) = "Regridding only implemented up to dimension 3"
630 call messages_fatal(1)
631 end if
632 end function evaluate_polynomials
633 end function regridding_init
634
635 subroutine regridding_finalize(this)
636 type(regridding_t), intent(inout) :: this
637
638 push_sub(regridding_finalize)
639
640 call partition_transfer_end(this%partition_transfer)
641 safe_deallocate_a(this%eta)
642 safe_deallocate_a(this%order_in)
643 safe_deallocate_a(this%order_in_global)
644 safe_deallocate_a(this%order_out)
645 safe_deallocate_a(this%order_out_global)
646 safe_deallocate_a(this%weights)
647 select case (this%scale_norms)
648 case(scale_none)
649 ! do nothing
650 case(scale_norm2)
651 safe_deallocate_a(this%overlap_map)
652 end select
653
654 pop_sub(regridding_finalize)
655 end subroutine regridding_finalize
656
657#include "real.F90"
658#include "regridding_inc.F90"
659#include "undef.F90"
660
661#include "complex.F90"
662#include "regridding_inc.F90"
663#include "undef.F90"
664
665end module regridding_oct_m
double floor(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_huge
Definition: global.F90:205
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_epsilon
Definition: global.F90:203
real(real64), parameter, public m_one
Definition: global.F90:188
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:728
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
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:967
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:420
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
integer, parameter nearest_neighbor
Definition: regridding.F90:226
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:237
subroutine regridding_finalize(this)
Definition: regridding.F90:729
integer, parameter scale_norm2
Definition: regridding.F90:226
integer, parameter scale_none
Definition: regridding.F90:226
This module defines routines, generating operators for a cubic stencil.
subroutine, public stencil_cube_get_lapl(this, dim, order)
This module defines stencils used in Octopus.
Definition: stencil.F90:135
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:611
real(real64) function, dimension(1:2 **this%dim) evaluate_polynomials(x)
Definition: regridding.F90:701
subroutine insert_global_point(mesh, ipg, ii)
Definition: regridding.F90:670
Describes mesh distribution to nodes.
Definition: mesh.F90:186
contains the information of the meshes and provides the transfer functions
Definition: regridding.F90:197
int true(void)