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