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