Octopus
submesh.F90
Go to the documentation of this file.
1!! Copyright (C) 2007 X. Andrade
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
19#include "global.h"
20
21module submesh_oct_m
22 use accel_oct_m
23 use batch_oct_m
25 use box_oct_m
26 use debug_oct_m
27 use global_oct_m
28 use index_oct_m
29 use, intrinsic :: iso_fortran_env
33 use sort_oct_m
34 use mesh_oct_m
37 use mpi_oct_m
40 use space_oct_m
41 use types_oct_m
42
43 implicit none
44 private
45
46 public :: &
47 submesh_t, &
58 dsm_nrm2, &
59 zsm_nrm2, &
79
82 type submesh_t
83 ! Components are public by default
84 real(real64), allocatable :: center(:)
85 real(real64) :: radius = m_zero
86 class(box_t), pointer :: box => null()
87 integer :: np = -1
88 integer, allocatable :: map(:)
89 integer :: num_regions
90 integer, allocatable :: regions(:)
91 type(accel_mem_t) :: buff_map
92 real(real64), allocatable :: rel_x(:,:)
93 real(real64), allocatable :: r(:)
96 real(real64), allocatable :: vol_pp(:)
97 type(mesh_t), pointer :: mesh => null()
98 logical :: overlap
100 integer :: np_global = -1
101 real(real64), allocatable :: rel_x_global(:,:)
102 integer, allocatable :: part_v(:)
103 integer, allocatable :: global2local(:)
104
105 type(mesh_cube_map_t) :: cube_map
106 end type submesh_t
107
108 interface submesh_add_to_mesh
110 end interface submesh_add_to_mesh
111
112 interface submesh_to_mesh_dotp
114 end interface submesh_to_mesh_dotp
115
116contains
117
118 ! -------------------------------------------------------------
119 ! Multipliers for recursive formulation of n-ellipsoid volume
120 ! simplifying the Gamma function
121 ! f(n) = 2f(n-2)/n, f(0)=1, f(1)=2
122 recursive real(real64) function f_n(dims) result(fn)
123 integer :: dims
124
125 if (dims == 0) then
126 fn = m_one
127 else if (dims == 1) then
128 fn = m_two
129 else
130 fn = m_two * f_n(dims - 2) / dims
131 end if
132
133 end function f_n
134
135 ! -------------------------------------------------------------
136 subroutine submesh_init(this, space, mesh, latt, center, rc)
137 type(submesh_t), intent(inout) :: this
138 class(space_t), intent(in) :: space
139 class(mesh_t), target, intent(in) :: mesh
140 type(lattice_vectors_t), intent(in) :: latt
141 real(real64), intent(in) :: center(1:space%dim)
142 real(real64), intent(in) :: rc
143
144 real(real64) :: r2, rc2, xx(space%dim), rc_norm_n
145 real(real64), allocatable :: center_copies(:,:), xtmp(:, :), rtmp(:)
146 integer :: icell, is, ip, ix, iy, iz
147 integer(int64) :: max_elements_count
148 type(lattice_iterator_t) :: latt_iter
149 integer, allocatable :: map_inv(:), map_temp(:)
150 integer :: nmax(3), nmin(3)
151 real(real64), parameter :: tol = 1e-13_real64
152
153
154 push_sub(submesh_init)
155 call profiling_in("SUBMESH_INIT")
156
157 assert(space%dim <= 3)
158
159 this%mesh => mesh
160
161 safe_allocate(this%center(1:space%dim))
162 this%center(:) = center(:)
163
164 this%radius = rc
165 ! We add a small number of avoid instabilities due to rounding errors
166 rc2 = rc**2 + tol
167
168 ! The spheres are generated differently for periodic coordinates,
169 ! mainly for performance reasons.
170 if (.not. space%is_periodic()) then
171
172 call profiling_in("SUBMESH_INIT_MAP_INV")
173 safe_allocate(map_inv(0:this%mesh%np))
174 map_inv(0:this%mesh%np) = 0
175
176 nmin = 0
177 nmax = 0
178
179 ! get a cube of points that contains the sphere
180 nmin(1:space%dim) = int((center(1:space%dim) - abs(rc))/mesh%spacing(1:space%dim)) - 1
181 nmax(1:space%dim) = int((center(1:space%dim) + abs(rc))/mesh%spacing(1:space%dim)) + 1
183 ! make sure that the cube is inside the grid
184 ! parts of the cube which would fall outside the simulation box are chopped off.
185 nmin(1:space%dim) = max(mesh%idx%nr(1, 1:space%dim), nmin(1:space%dim))
186 nmax(1:space%dim) = min(mesh%idx%nr(2, 1:space%dim), nmax(1:space%dim))
188 ! Get the total number of points inside the sphere
189 is = 0 ! this index counts inner points
190 do iz = nmin(3), nmax(3)
191 do iy = nmin(2), nmax(2)
192 do ix = nmin(1), nmax(1)
193 ip = mesh_local_index_from_coords(mesh, [ix, iy, iz])
194 if (ip == 0 .or. ip > mesh%np) cycle
195 r2 = sum((mesh%x(:, ip) - center)**2)
196 if (r2 <= rc2) then
197 is = is + 1
198 map_inv(ip) = is
199 end if
200 end do
201 end do
202 end do
203 this%np = is
204 call profiling_out("SUBMESH_INIT_MAP_INV")
205
206 call profiling_in("SUBMESH_INIT_RTMP")
207 safe_allocate(this%map(1:this%np))
208 safe_allocate(xtmp(1:space%dim, 1:this%np))
209 safe_allocate(rtmp(1:this%np))
210
211 ! Generate the table and the positions
212 do iz = nmin(3), nmax(3)
213 do iy = nmin(2), nmax(2)
214 do ix = nmin(1), nmax(1)
215 ip = mesh_local_index_from_coords(mesh, [ix, iy, iz])
216 if (ip == 0 .or. ip > mesh%np) cycle
217 is = map_inv(ip)
218 if (is == 0) cycle
219 this%map(is) = ip
220 xtmp(:, is) = mesh%x(:, ip) - center
221 rtmp(is) = norm2(xtmp(:,is))
222 end do
223 end do
224 end do
225
226 safe_deallocate_a(map_inv)
227 call profiling_out("SUBMESH_INIT_RTMP")
228
229 ! This is the case for a periodic system
230 else
232 ! Get the total number of points inside the sphere considering
233 ! replicas along PBCs
234
235 ! this requires some optimization
236
237 ! We use non-zero centered periodic copies to minimize the number of cells to test.
238 ! By passing the center (in reduced coordinates), the iterator only keeps the cells that are actually relevant
239 latt_iter = lattice_iterator_t(latt, rc, center=latt%cart_to_red(center) - mesh%red_min(space))
240
241 ! We get the shifted centers for the cells we care about
242 safe_allocate(center_copies(1:space%dim, 1:latt_iter%n_cells))
243 do icell = 1, latt_iter%n_cells
244 center_copies(:, icell) = center + latt_iter%get(icell)
245 end do
246
247 !Recursive formulation for the volume of n-ellipsoid
248 !Garry Tee, NZ J. Mathematics Vol. 34 (2005) p. 165 eqs. 53,55
249 rc_norm_n = product(ceiling(rc / mesh%spacing(1:space%dim), int64) + m_one)
250 if (mesh%use_vol_pp) rc_norm_n = rc_norm_n / mesh%coord_system%min_mesh_scaling_product
251 max_elements_count = 3**space%dim * int(m_pi**floor(0.5 * space%dim) * rc_norm_n * f_n(space%dim), int64)
252
253 call profiling_in("SUBMESH_INIT_PERIODIC_R")
254 safe_allocate(map_temp(1:max_elements_count))
255 safe_allocate(xtmp(1:space%dim, 1:max_elements_count))
256 safe_allocate(rtmp(1:max_elements_count))
257
258 is = 0
259 do ip = 1, mesh%np
260 do icell = 1, latt_iter%n_cells
261 xx = mesh%x(:,ip) - center_copies(:, icell)
262 if(any(abs(xx)>rc+tol)) cycle
263 r2 = sum(xx**2)
264 if (r2 > rc2) cycle
265 is = is + 1
266 map_temp(is) = ip
267 rtmp(is) = sqrt(r2)
268 xtmp(:, is) = xx
269 ! Note that xx can be outside the unit cell
270 end do
271 end do
272 assert(is < huge(is))
273 this%np = is
274
275 safe_allocate(this%map(1:this%np))
276 this%map(1:this%np) = map_temp(1:this%np)
277 call profiling_out("SUBMESH_INIT_PERIODIC_R")
278
279 safe_deallocate_a(map_temp)
280 safe_deallocate_a(center_copies)
281
282 end if
283
284 call submesh_reorder_points(this, space, xtmp, rtmp)
285 call profiling_out("SUBMESH_INIT")
286
287 safe_deallocate_a(xtmp)
288 safe_deallocate_a(rtmp)
289
290 call submesh_get_vol_pp(this)
291
292 pop_sub(submesh_init)
293 end subroutine submesh_init
294
295 ! --------------------------------------------------------------
300 subroutine submesh_get_vol_pp(this)
301 type(submesh_t), intent(inout) :: this
302
303 integer :: is
304
305 if (.not. this%mesh%use_vol_pp) return
306
307 push_sub(submesh_get_vol_pp)
308
309 ! submesh_broadcast calls this again on the root rank
310 safe_deallocate_a(this%vol_pp)
311 safe_allocate(this%vol_pp(1:this%np))
312 do is = 1, this%np
313 this%vol_pp(is) = this%mesh%vol_pp(this%map(is))
314 end do
315
316 pop_sub(submesh_get_vol_pp)
317 end subroutine submesh_get_vol_pp
318
319 subroutine submesh_reorder_points(this, space, xtmp, rtmp)
320 type(submesh_t), intent(inout) :: this
321 class(space_t), intent(in) :: space
322 real(real64), contiguous, intent(in) :: xtmp(:, :), rtmp(:)
323
324 integer :: ip, i_region, offset
325 integer, allocatable :: order(:), order_new(:)
326 integer, allocatable :: map_new(:)
327 integer, allocatable :: np_region(:), tmp_array(:)
328
329 push_sub(submesh_reorder_points)
330
331 ! now order points for better locality
332
333 call profiling_in("SUBMESH_INIT_ORDER")
334 safe_allocate(order(1:this%np))
335 safe_allocate(this%rel_x(1:space%dim, 1:this%np))
336 safe_allocate(this%r(1:this%np))
337
338 do ip = 1, this%np
339 order(ip) = ip
340 end do
341
342 ! First we just reorder in order to determine overlap:
343 call sort(this%map, order)
344
345 !check whether points overlap (i.e. whether a submesh contains the same point more than once)
346 this%overlap = .false.
347 do ip = 1, this%np - 1
348 if (this%map(ip) == this%map(ip + 1)) then
349 ! this simplified test works, as the points are ordered.
350 this%overlap = .true.
351 exit
352 end if
353 end do
354
355 this%num_regions = 1
356 call profiling_out("SUBMESH_INIT_ORDER")
357
358 if(this%overlap) then
359 call profiling_in("SUBMESH_INIT_OVERLAP")
360 !disentangle the map into injective regions
361
362 safe_allocate(tmp_array(1:this%np))
363 safe_allocate(order_new(1:this%np))
364 safe_allocate(np_region(1:this%np))
365 safe_allocate(map_new( 1:this%np))
366
367 np_region(1) = 1
368 tmp_array(1) = 1
369 i_region = 1
370
371 do ip = 2, this%np
372 if (this%map(ip) == this%map(ip - 1)) then
373 i_region = i_region + 1
374 if (i_region > this%num_regions) then
375 this%num_regions = i_region
376 np_region(i_region) = 0
377 end if
378 else
379 i_region = 1
380 end if
381 tmp_array(ip) = i_region ! which region does ip belong to
382 np_region(i_region) = np_region(i_region) + 1 ! increase number of points in i_region
383 end do
384
385 assert( .not. allocated(this%regions))
386
387 ! construct array of offsets
388 safe_allocate(this%regions(1:this%num_regions+1))
389
390 this%regions(1) = 1
391
392 if(this%num_regions > 1) then
393 do i_region = 1, this%num_regions
394 this%regions(i_region + 1) = this%regions(i_region) + np_region(i_region)
395 end do
396 else
397 this%regions(2) = this%np + 1
398 end if
399
400 np_region(1:this%np) = 0
401 order_new(1:this%np) = -1
402 map_new(1:this%np) = -1
403
404
405 !reassemble regions into global map array
406 do ip = 1, this%np
407 i_region = tmp_array(ip)
408 np_region(i_region) = np_region(i_region) + 1
409 offset = this%regions(i_region) - 1
410 map_new( offset + np_region(i_region) ) = this%map(ip)
411 order_new( offset + np_region(i_region) ) = order(ip)
412 end do
413
414 order(1:this%np) = order_new(1:this%np)
415 this%map(1:this%np) = map_new(1:this%np)
416
417 safe_deallocate_a(tmp_array)
418 safe_deallocate_a(order_new)
419 safe_deallocate_a(np_region)
420 safe_deallocate_a(map_new)
421 call profiling_out("SUBMESH_INIT_OVERLAP")
422
423 else
424 this%num_regions = 1
425 safe_allocate(this%regions(1:2))
426 this%regions(1) = 1
427 this%regions(2) = this%np + 1
428 end if
429
430 ! Lastly, reorder the points according to the new scheme
431 do ip = 1, this%np
432 this%rel_x(:, ip) = xtmp(:, order(ip))
433 this%r(ip) = rtmp(order(ip))
434 end do
435
436 safe_deallocate_a(order)
437
439 end subroutine submesh_reorder_points
440
441
442 ! --------------------------------------------------------------
443 !This routine takes two submeshes and merge them into a bigger submesh
444 !The grid is centered on the first center
445 subroutine submesh_merge(this, space, mesh, sm1, sm2, shift)
446 type(submesh_t), intent(inout) :: this
447 class(space_t), intent(in) :: space
448 class(mesh_t), target, intent(in) :: mesh
449 type(submesh_t), intent(in) :: sm1
450 type(submesh_t), intent(in) :: sm2
451 real(real64), optional, intent(in) :: shift(:)
452
453 real(real64) :: r2
454 integer :: ip, is
455 real(real64) :: xx(space%dim), diff_centers(space%dim)
456
457 push_sub(submesh_merge)
458 call profiling_in("SUBMESH_MERGE")
459
460 this%mesh => mesh
461
462 safe_allocate(this%center(1:space%dim))
463 this%center(:) = sm1%center(:)
464 this%radius = sm1%radius
465
466 ! This is a quick fix to prevent uninitialized variables. To properly check the self-overlap,
467 ! a similar approach as in submesh_init should be taken with respect to the merged map.
468 this%overlap = sm1%overlap .or. sm2%overlap
469
470 diff_centers = sm1%center - sm2%center
471 if (present(shift)) diff_centers = diff_centers - shift
472
473 !As we take the union of the two submeshes, we know that we have all the points from the first one included.
474 !The extra points from the second submesh are those which are not included in the first one
475 is = sm1%np
476 do ip = 1, sm2%np
477 !sm2%x contains points coordinates defined with respect to sm2%center
478 xx = sm2%rel_x(:, ip) - diff_centers
479 !If the point is not in sm1, we add it
480 if (sum(xx**2) > sm1%radius**2) is = is + 1
481 end do
482
483 this%np = is
484
485 safe_allocate(this%map(1:this%np))
486 safe_allocate(this%rel_x(1:space%dim, 1:this%np))
487 safe_allocate(this%r(1:this%np))
488 this%map(1:sm1%np) = sm1%map(1:sm1%np)
489 this%rel_x(:, 1:sm1%np) = sm1%rel_x(:, 1:sm1%np)
490 this%r(1:sm1%np) = sm1%r(1:sm1%np)
491
492 !iterate again to fill the tables
493 is = sm1%np
494 do ip = 1, sm2%np
495 xx = sm2%rel_x(:, ip) - diff_centers
496 r2 = sum(xx**2)
497 if (r2 > sm1%radius**2) then
498 is = is + 1
499 this%map(is) = sm2%map(ip)
500 this%r(is) = sqrt(r2)
501 this%rel_x(:, is) = xx
502 end if
503 end do
504
505 call submesh_get_vol_pp(this)
506
507 call profiling_out("SUBMESH_MERGE")
508 pop_sub(submesh_merge)
509 end subroutine submesh_merge
510
511 ! --------------------------------------------------------------
512 !This routine shifts the center of a submesh, without changing the grid points
513 subroutine submesh_shift_center(this, space, newcenter)
514 type(submesh_t), intent(inout) :: this
515 class(space_t), intent(in) :: space
516 real(real64), intent(in) :: newcenter(:)
517
518 real(real64) :: xx(space%dim), diff_centers(space%dim), oldcenter(space%dim)
519 integer :: ip
520
521 push_sub(submesh_shift_center)
522 call profiling_in("SUBMESH_SHIFT")
523
524 oldcenter = this%center
525 this%center(:) = newcenter(:)
526
527 diff_centers = newcenter - oldcenter
528
529 do ip = 1, this%np
530 xx = this%rel_x(:, ip) - diff_centers
531 this%r(ip) = norm2(xx)
532 this%rel_x(:, ip) = xx
533 end do
534
535 call profiling_out("SUBMESH_SHIFT")
536 pop_sub(submesh_shift_center)
537 end subroutine submesh_shift_center
538
539 ! --------------------------------------------------------------
540 subroutine submesh_broadcast(this, space, mesh, center, radius, root, mpi_grp)
541 type(submesh_t), intent(inout) :: this
542 class(space_t), intent(in) :: space
543 type(mesh_t), target, intent(in) :: mesh
544 real(real64), intent(in) :: center(1:space%dim)
545 real(real64), intent(in) :: radius
546 integer, intent(in) :: root
547 type(mpi_grp_t), intent(in) :: mpi_grp
548
549 integer :: nparray(1:3)
550
551 push_sub(submesh_broadcast)
552 call profiling_in('SUBMESH_BCAST')
553
554 if (root /= mpi_grp%rank) then
555 this%mesh => mesh
556 safe_allocate(this%center(1:space%dim))
557 this%center(:) = center(:)
558 this%radius = radius
559 end if
560
561 if (mpi_grp%size > 1) then
562
563 if (root == mpi_grp%rank) then
564 nparray(1) = this%np
565 nparray(2) = this%num_regions
566 if (this%overlap) then
567 nparray(3) = 1
568 else
569 nparray(3) = 0
570 end if
571 end if
572
573 call mpi_grp%bcast(nparray, 3, mpi_integer, root)
574 this%np = nparray(1)
575 this%num_regions = nparray(2)
576 this%overlap = (nparray(3) == 1)
577
578 if (root /= mpi_grp%rank) then
579 safe_allocate(this%map(1:this%np))
580 safe_allocate(this%rel_x(1:space%dim, 1:this%np))
581 safe_allocate(this%r(1:this%np))
582 safe_allocate(this%regions(1:this%num_regions+1))
583 end if
584
585 call mpi_grp%bcast(this%regions(1), this%num_regions+1, mpi_integer, root)
586
587 if (this%np > 0) then
588 call mpi_grp%bcast(this%map(1), this%np, mpi_integer, root)
589 call mpi_grp%bcast(this%rel_x(1, 1), this%np*space%dim, mpi_double_precision, root)
590 call mpi_grp%bcast(this%r(1), this%np, mpi_double_precision, root)
591 end if
592
593 end if
594
595 call submesh_get_vol_pp(this)
596
597 call profiling_out('SUBMESH_BCAST')
598 pop_sub(submesh_broadcast)
599 end subroutine submesh_broadcast
600
601 ! --------------------------------------------------------------
602 logical function submesh_compatible(this, radius, center, dx) result(compatible)
603 type(submesh_t), intent(in) :: this
604 real(real64), intent(in) :: radius
605 real(real64), intent(in) :: center(:)
606 real(real64), intent(in) :: dx
607
608 compatible =.false.
609 if (allocated(this%center)) then
612 if (radius <= this%radius+dx*1e-6_real64 .and. all(abs(this%center - center) < 0.25*dx)) then
613 compatible = .true.
614 end if
615 end if
616
617 end function submesh_compatible
618
619 ! --------------------------------------------------------------
620 subroutine submesh_end(this)
621 type(submesh_t), intent(inout) :: this
622
623 push_sub(submesh_end)
624
625 nullify(this%mesh)
626 nullify(this%box)
627 if (this%np /= -1) then
628 this%np = -1
629 safe_deallocate_a(this%center)
630 safe_deallocate_a(this%map)
631 safe_deallocate_a(this%rel_x)
632 safe_deallocate_a(this%r)
633 safe_deallocate_a(this%vol_pp)
634 safe_deallocate_a(this%regions)
635 end if
636
637 if (accel_is_enabled()) then
638 call accel_free_buffer(this%buff_map)
639 end if
640
641 pop_sub(submesh_end)
642 end subroutine submesh_end
643
644
645 ! --------------------------------------------------------------
646 logical function submesh_overlap(sm1, sm2, space) result(overlap)
647 type(submesh_t), intent(in) :: sm1
648 type(submesh_t), intent(in) :: sm2
649 class(space_t), intent(in) :: space
650
651 integer :: ii, jj, dd
652 real(real64) :: distance
653
654 !no PUSH_SUB, called too often
655
656 if (.not. space%is_periodic()) then
657 !first check the distance
658 distance = sum((sm1%center - sm2%center)**2)
659 overlap = distance <= (1.5_real64*(sm1%radius + sm2%radius))**2
660
661 ! if they are very far, no need to check in detail
662 if (.not. overlap) return
663 end if
664
665 ! Otherwise check whether they have the some point in common. We
666 ! can make the comparison faster using that the arrays are sorted.
667 overlap = .false.
668 ii = 1
669 jj = 1
670 do while(ii <= sm1%np .and. jj <= sm2%np)
671 dd = sm1%map(ii) - sm2%map(jj)
672 if (dd < 0) then
673 ii = ii + 1
674 else if (dd > 0) then
675 jj = jj + 1
676 else
677 overlap = .true.
678 exit
679 end if
680 end do
681
682 if (sm1%mesh%parallel_in_domains) then
683 call sm1%mesh%mpi_grp%allreduce_inplace(overlap, 1, mpi_logical, mpi_lor)
684 end if
685
686 end function submesh_overlap
687
688 ! -------------------------------------------------------------
689 subroutine submesh_build_global(this, space)
690 type(submesh_t), intent(inout) :: this
691 class(space_t), intent(in) :: space
692
693 integer, allocatable :: part_np(:)
694 integer :: ipart, ind, ip
695
696 push_sub(submesh_build_global)
698 if (.not. this%mesh%parallel_in_domains) then
699 this%np_global = this%np
700 pop_sub(submesh_build_global)
701 return
702 end if
703
704 safe_allocate(part_np(this%mesh%pv%npart))
705 part_np = 0
706 part_np(this%mesh%pv%partno) = this%np
707
708 call this%mesh%allreduce(part_np)
709 this%np_global = sum(part_np)
710
711 safe_allocate(this%rel_x_global(1:space%dim, 1:this%np_global))
712 safe_allocate(this%part_v(1:this%np_global))
713 safe_allocate(this%global2local(1:this%np_global))
714 this%rel_x_global(1:space%dim, 1:this%np_global) = m_zero
715 this%part_v(1:this%np_global) = 0
716 this%global2local(1:this%np_global) = 0
717
718 ind = 0
719 do ipart = 1, this%mesh%pv%npart
720 if (ipart == this%mesh%pv%partno) then
721 do ip = 1, this%np
722 this%rel_x_global(:, ind + ip) = this%rel_x(:, ip)
723 this%part_v(ind + ip) = this%mesh%pv%partno
724 this%global2local(ind + ip) = ip
725 end do
726 end if
727 ind = ind + part_np(ipart)
728 end do
729
730 call this%mesh%allreduce(this%rel_x_global)
731 call this%mesh%allreduce(this%part_v)
732 call this%mesh%allreduce(this%global2local)
733
734 safe_deallocate_a(part_np)
735
736 pop_sub(submesh_build_global)
737 end subroutine submesh_build_global
738
739 ! -----------------------------------------------------------
740 subroutine submesh_end_global(this)
741 type(submesh_t), intent(inout) :: this
742
743 push_sub(submesh_end_global)
744
745 safe_deallocate_a(this%rel_x_global)
746 this%np_global = -1
747 safe_deallocate_a(this%part_v)
748 safe_deallocate_a(this%global2local)
749
750 pop_sub(submesh_end_global)
751 end subroutine submesh_end_global
752
753
754 ! -----------------------------------------------------------
755 subroutine zzsubmesh_add_to_mesh(this, sphi, phi, factor)
756 type(submesh_t), intent(in) :: this
757 complex(real64), contiguous, intent(in) :: sphi(:)
758 complex(real64), contiguous, intent(inout) :: phi(:)
759 complex(real64), optional, intent(in) :: factor
760
761 integer :: ip, m
762
763 push_sub(zzsubmesh_add_to_mesh)
764
765 if (present(factor)) then
766 !Loop unrolling inspired by BLAS axpy routine
767 m = mod(this%np,4)
768 do ip = 1, m
769 phi(this%map(ip)) = phi(this%map(ip)) + factor*sphi(ip)
770 end do
771 if (this%np.ge.4) then
772 do ip = m+1, this%np, 4
773 phi(this%map(ip)) = phi(this%map(ip)) + factor*sphi(ip)
774 phi(this%map(ip+1)) = phi(this%map(ip+1)) + factor*sphi(ip+1)
775 phi(this%map(ip+2)) = phi(this%map(ip+2)) + factor*sphi(ip+2)
776 phi(this%map(ip+3)) = phi(this%map(ip+3)) + factor*sphi(ip+3)
777 end do
778 end if
779 else
780 m = mod(this%np,4)
781 do ip = 1, m
782 phi(this%map(ip)) = phi(this%map(ip)) + sphi(ip)
783 end do
784 if (this%np.ge.4) then
785 do ip = m+1, this%np, 4
786 phi(this%map(ip)) = phi(this%map(ip)) + sphi(ip)
787 phi(this%map(ip+1)) = phi(this%map(ip+1)) + sphi(ip+1)
788 phi(this%map(ip+2)) = phi(this%map(ip+2)) + sphi(ip+2)
789 phi(this%map(ip+3)) = phi(this%map(ip+3)) + sphi(ip+3)
790 end do
791 end if
792 end if
793
794 pop_sub(zzsubmesh_add_to_mesh)
795 end subroutine zzsubmesh_add_to_mesh
796
797 !------------------------------------------------------------
798 complex(real64) function zzsubmesh_to_mesh_dotp(this, sphi, phi, reduce) result(dotp)
799 type(submesh_t), intent(in) :: this
800 complex(real64), contiguous, intent(in) :: sphi(:)
801 complex(real64), contiguous, intent(in) :: phi(:)
802 logical, optional, intent(in) :: reduce
803
804 integer :: is, m, ip
805
806 push_sub(zzsubmesh_to_mesh_dotp)
807
808 dotp = m_z0
809
810 if (this%mesh%use_vol_pp) then
811 do is = 1, this%np
812 dotp = dotp + this%vol_pp(is)*phi(this%map(is))*conjg(sphi(is))
813 end do
814 else
815 m = mod(this%np,4)
816 do ip = 1, m
817 dotp = dotp + phi(this%map(ip))*conjg(sphi(ip))
818 end do
819 if (this%np.ge.4) then
820 do ip = m+1, this%np, 4
821 dotp = dotp + phi(this%map(ip))*conjg(sphi(ip)) &
822 + phi(this%map(ip+1))*conjg(sphi(ip+1)) &
823 + phi(this%map(ip+2))*conjg(sphi(ip+2)) &
824 + phi(this%map(ip+3))*conjg(sphi(ip+3))
825 end do
826 end if
827 dotp = dotp*this%mesh%vol_pp(1)
828 end if
829
830 if (optional_default(reduce, .true.)) then
831 call profiling_in("SM_REDUCE_DOTP")
832 call this%mesh%allreduce(dotp)
833 call profiling_out("SM_REDUCE_DOTP")
834 end if
837 end function zzsubmesh_to_mesh_dotp
838
839 !------------------------------------------------------------
841 subroutine submesh_get_cube_dim(sm, space, db)
842 type(submesh_t), target, intent(in) :: sm
843 class(space_t), intent(in) :: space
844 integer, intent(out) :: db(1:space%dim)
845
846 integer :: ip, idir
847 real(real64) :: chi(space%dim), max_chi(space%dim)
848 integer :: db_red(1:space%dim)
849 real(real64), parameter :: tol=1.0e-10_real64
851 push_sub(submesh_get_cube_dim)
852
853 max_chi = m_zero
854 do ip = 1, sm%np
855 chi = sm%mesh%coord_system%from_cartesian(sm%rel_x(:, ip))
856 do idir = 1, space%dim
857 max_chi(idir) = max(max_chi(idir), abs(chi(idir))/sm%mesh%spacing(idir))
858 end do
859 end do
860
861 do idir = 1, space%dim
862 db(idir) = nint(max_chi(idir)-tol)
863 end do
864
865 if(sm%mesh%parallel_in_domains) then
866 call sm%mesh%mpi_grp%allreduce(db(1), db_red(1), space%dim, mpi_integer, mpi_max)
867 db(1:space%dim) = db_red(1:space%dim)
868 end if
869
870 db = 2 * db + 1
871
872 pop_sub(submesh_get_cube_dim)
873 end subroutine submesh_get_cube_dim
874
875 !------------------------------------------------------------
876 subroutine submesh_init_cube_map(sm, space)
877 type(submesh_t), target, intent(inout) :: sm
878 class(space_t), intent(in) :: space
879
880 integer(int64) :: ip
881 integer ::idir
882 real(real64) :: chi(space%dim), shift(space%dim)
883
884 push_sub(submesh_init_cube_map)
885
886 sm%cube_map%nmap = sm%np
887
888 safe_allocate(sm%cube_map%map(1:space%dim, 1:sm%cube_map%nmap))
889
890 !The center of the submesh does not belong to the mesh
891 !So we first need to find the closest grid point, and center the cube to it
892 chi = sm%mesh%coord_system%from_cartesian(sm%center)
893 do idir = 1, space%dim
894 shift(idir) = nint(chi(idir)/sm%mesh%spacing(idir))*sm%mesh%spacing(idir)
895 end do
896 shift = sm%mesh%coord_system%to_cartesian(shift)
897 shift = shift - sm%center
898
899 do ip = 1, sm%cube_map%nmap
900 chi = sm%mesh%coord_system%from_cartesian(sm%rel_x(:,ip) - shift)
901 do idir = 1, space%dim
902 sm%cube_map%map(idir, ip) = nint(chi(idir)/sm%mesh%spacing(idir))
903 end do
904 end do
905
906 if (accel_is_enabled()) then
907 call accel_create_buffer(sm%cube_map%map_buffer, accel_mem_read_only, type_integer, sm%cube_map%nmap*space%dim)
908 call accel_write_buffer(sm%cube_map%map_buffer, space%dim, sm%cube_map%nmap, sm%cube_map%map)
909 end if
910
911 pop_sub(submesh_init_cube_map)
912 end subroutine submesh_init_cube_map
913
914 !------------------------------------------------------------
915 subroutine submesh_end_cube_map(sm)
916 type(submesh_t), intent(inout) :: sm
917
918 push_sub(submesh_end_cube_map)
919
920 call mesh_cube_map_end(sm%cube_map)
921
922 pop_sub(submesh_end_cube_map)
923 end subroutine submesh_end_cube_map
924
931 subroutine dzsubmesh_batch_add(this, ss, mm)
932 type(submesh_t), intent(in) :: this
933 class(batch_t), intent(in) :: ss
934 class(batch_t), intent(inout) :: mm
935
936 integer :: ist, idim, jdim, is
937
938 push_sub(dzsubmesh_batch_add)
939
940 assert(.not. mm%is_packed())
941 assert(ss%type() == type_float)
942 assert(mm%type() == type_cmplx)
943 assert(ss%nst_linear == mm%nst_linear)
944 assert(ss%status() == mm%status())
945 assert(ss%dim == mm%dim)
946
947 assert(mm%nst == ss%nst)
948
949 !$omp parallel do private(ist, idim, jdim, is) if(.not. this%overlap)
950 do ist = 1, mm%nst
951 do idim = 1, mm%dim
952 jdim = min(idim, ss%dim)
953
954 do is = 1, this%np
955 mm%zff(this%map(is), idim, ist) = &
956 mm%zff(this%map(is), idim, ist) + ss%dff(is, jdim, ist)
957 end do
958
959 end do
960 end do
961 !$omp end parallel do
962
963 pop_sub(dzsubmesh_batch_add)
964 end subroutine dzsubmesh_batch_add
965
966
967#include "undef.F90"
968#include "real.F90"
969#include "submesh_inc.F90"
970
971#include "undef.F90"
972#include "complex.F90"
973#include "submesh_inc.F90"
974
975end module submesh_oct_m
976
977!! Local Variables:
978!! mode: f90
979!! coding: utf-8
980!! End:
This is the common interface to a sorting routine. It performs the shell algorithm,...
Definition: sort.F90:156
double sqrt(double __x) __attribute__((__nothrow__
double floor(double __x) __attribute__((__nothrow__
double fn(const gsl_vector *v, void *params)
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:990
pure logical function, public accel_is_enabled()
Definition: accel.F90:414
integer, parameter, public accel_mem_read_only
Definition: accel.F90:185
This module implements batches of mesh functions.
Definition: batch.F90:135
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:124
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:198
complex(real64), parameter, public m_z0
Definition: global.F90:210
real(real64), parameter, public m_one
Definition: global.F90:201
This module implements the index, used for the mesh points.
Definition: index.F90:124
subroutine, public mesh_cube_map_end(this)
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
integer function, public mesh_local_index_from_coords(mesh, ix)
This function returns the local index of the point for a given vector of integer coordinates.
Definition: mesh.F90:947
Some general things and nomenclature:
Definition: par_vec.F90:173
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:668
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:600
This module is intended to contain "only mathematical" functions and procedures.
Definition: sort.F90:119
real(real64) function, public dsm_integrate_frommesh(mesh, sm, ff, reduce)
Definition: submesh.F90:1176
subroutine zdsubmesh_add_to_mesh(this, sphi, phi, factor)
Definition: submesh.F90:1822
subroutine, public submesh_init_cube_map(sm, space)
Definition: submesh.F90:972
logical function, public submesh_overlap(sm1, sm2, space)
Definition: submesh.F90:742
subroutine, public zsubmesh_batch_dotp_matrix(this, mm, ss, dot, reduce)
Definition: submesh.F90:2174
real(real64) function, public dsm_nrm2(sm, ff, reduce)
this function returns the the norm of a vector
Definition: submesh.F90:1299
subroutine zzsubmesh_add_to_mesh(this, sphi, phi, factor)
Definition: submesh.F90:851
subroutine submesh_get_vol_pp(this)
Gather the per-point volume elements of the sphere from the mesh.
Definition: submesh.F90:396
subroutine, public submesh_end_global(this)
Definition: submesh.F90:836
subroutine, public zsubmesh_copy_from_mesh(this, phi, sphi, conjugate)
Definition: submesh.F90:1870
subroutine submesh_reorder_points(this, space, xtmp, rtmp)
Definition: submesh.F90:415
complex(real64) function, public zsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1732
complex(real64) function, public zsubmesh_dotp(this, f1, f2, reduce)
dot product of two functions defined on the submesh
Definition: submesh.F90:1940
subroutine, public submesh_shift_center(this, space, newcenter)
Definition: submesh.F90:609
complex(real64) function zzsubmesh_to_mesh_dotp(this, sphi, phi, reduce)
Definition: submesh.F90:894
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1131
subroutine, public dsubmesh_batch_add_matrix(this, factor, ss, mm)
The following functions takes a batch of functions defined in submesh (ss) and adds all of them to ea...
Definition: submesh.F90:1428
recursive real(real64) function f_n(dims)
Definition: submesh.F90:218
subroutine, public dsubmesh_copy_from_mesh(this, phi, sphi, conjugate)
Definition: submesh.F90:1269
real(real64) function ddsubmesh_to_mesh_dotp(this, sphi, phi, reduce)
Definition: submesh.F90:1383
subroutine, public submesh_merge(this, space, mesh, sm1, sm2, shift)
Definition: submesh.F90:541
subroutine, public dzsubmesh_batch_add(this, ss, mm)
The following function takes a batch of functions defined in submesh (ss) and adds one of them to eac...
Definition: submesh.F90:1027
subroutine, public zsubmesh_batch_add(this, ss, mm)
The following function takes a batch of functions defined in submesh (ss) and adds one of them to eac...
Definition: submesh.F90:2122
real(real64) function, public zsm_nrm2(sm, ff, reduce)
this function returns the the norm of a vector
Definition: submesh.F90:1900
subroutine, public zsubmesh_batch_add_matrix(this, factor, ss, mm)
The following functions takes a batch of functions defined in submesh (ss) and adds all of them to ea...
Definition: submesh.F90:2029
subroutine, public submesh_end_cube_map(sm)
Definition: submesh.F90:1011
subroutine, public submesh_end(this)
Definition: submesh.F90:716
subroutine ddsubmesh_add_to_mesh(this, sphi, phi, factor)
Definition: submesh.F90:1221
subroutine, public submesh_get_cube_dim(sm, space, db)
finds the dimension of a box containing the submesh
Definition: submesh.F90:937
subroutine, public dsubmesh_batch_dotp_matrix(this, mm, ss, dot, reduce)
Definition: submesh.F90:1573
complex(real64) function, public zsm_integrate_frommesh(mesh, sm, ff, reduce)
Definition: submesh.F90:1777
logical function, public submesh_compatible(this, radius, center, dx)
Definition: submesh.F90:698
real(real64) function, public dsubmesh_dotp(this, f1, f2, reduce)
dot product of two functions defined on the submesh
Definition: submesh.F90:1339
subroutine, public submesh_build_global(this, space)
Definition: submesh.F90:785
subroutine, public submesh_broadcast(this, space, mesh, center, radius, root, mpi_grp)
Definition: submesh.F90:636
subroutine, public dsubmesh_batch_add(this, ss, mm)
The following function takes a batch of functions defined in submesh (ss) and adds one of them to eac...
Definition: submesh.F90:1521
subroutine, public submesh_init(this, space, mesh, latt, center, rc)
Definition: submesh.F90:232
complex(real64) function zdsubmesh_to_mesh_dotp(this, sphi, phi, reduce)
Definition: submesh.F90:1984
type(type_t), parameter, public type_cmplx
Definition: types.F90:137
type(type_t), parameter, public type_integer
Definition: types.F90:138
type(type_t), parameter, public type_float
Definition: types.F90:136
Class defining batches of mesh functions.
Definition: batch.F90:164
The following class implements a lattice iterator. It allows one to loop over all cells that are with...
Describes mesh distribution to nodes.
Definition: mesh.F90:188
This is defined even when running serial.
Definition: mpi.F90:144
A submesh is a type of mesh, used for the projectors in the pseudopotentials It contains points on a ...
Definition: submesh.F90:177
int true(void)
void distance(const int iatom, const int jatom, const double coordinates[], double *rr, double *rr2, double *rr6, double *rr7)
Definition: vdw_ts_low.c:2059