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