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 ! We use non-zero centered periodic copies to minimize the number of cells to test.
232 ! By passing the center (in reduced coordinates), the iterator only keeps the cells that are actually relevant
233 latt_iter = lattice_iterator_t(latt, rc, center=latt%cart_to_red(center) - mesh%red_min(space))
234
235 ! We get the shifted centers for the cells we care about
236 safe_allocate(center_copies(1:space%dim, 1:latt_iter%n_cells))
237 do icell = 1, latt_iter%n_cells
238 center_copies(:, icell) = center + latt_iter%get(icell)
239 end do
240
241 !Recursive formulation for the volume of n-ellipsoid
242 !Garry Tee, NZ J. Mathematics Vol. 34 (2005) p. 165 eqs. 53,55
243 rc_norm_n = product(ceiling(rc / mesh%spacing(1:space%dim), int64) + m_one)
244 if (mesh%use_curvilinear) rc_norm_n = rc_norm_n / mesh%coord_system%min_mesh_scaling_product
245 max_elements_count = 3**space%dim * int(m_pi**floor(0.5 * space%dim) * rc_norm_n * f_n(space%dim), int64)
246
247 call profiling_in("SUBMESH_INIT_PERIODIC_R")
248 safe_allocate(map_temp(1:max_elements_count))
249 safe_allocate(xtmp(1:space%dim, 1:max_elements_count))
250 safe_allocate(rtmp(1:max_elements_count))
251
252 is = 0
253 do ip = 1, mesh%np
254 do icell = 1, latt_iter%n_cells
255 xx = mesh%x(:,ip) - center_copies(:, icell)
256 if(any(abs(xx)>rc+tol)) cycle
257 r2 = sum(xx**2)
258 if (r2 > rc2) cycle
259 is = is + 1
260 map_temp(is) = ip
261 rtmp(is) = sqrt(r2)
262 xtmp(:, is) = xx
263 ! Note that xx can be outside the unit cell
264 end do
265 end do
266 assert(is < huge(is))
267 this%np = is
268
269 safe_allocate(this%map(1:this%np))
270 this%map(1:this%np) = map_temp(1:this%np)
271 call profiling_out("SUBMESH_INIT_PERIODIC_R")
272
273 safe_deallocate_a(map_temp)
274 safe_deallocate_a(center_copies)
275
276 end if
277
278 call submesh_reorder_points(this, space, xtmp, rtmp)
279 call profiling_out("SUBMESH_INIT")
280
281 safe_deallocate_a(xtmp)
282 safe_deallocate_a(rtmp)
283
284 pop_sub(submesh_init)
285 end subroutine submesh_init
286
287 subroutine submesh_reorder_points(this, space, xtmp, rtmp)
288 type(submesh_t), intent(inout) :: this
289 class(space_t), intent(in) :: space
290 real(real64), intent(in) :: xtmp(:, :), rtmp(:)
291
292 integer :: ip, i_region, offset
293 integer, allocatable :: order(:), order_new(:)
294 integer, allocatable :: map_new(:)
295 integer, allocatable :: np_region(:), tmp_array(:)
296
297 push_sub(submesh_reorder_points)
298
299 ! now order points for better locality
300
301 call profiling_in("SUBMESH_INIT_ORDER")
302 safe_allocate(order(1:this%np))
303 safe_allocate(this%rel_x(1:space%dim, 1:this%np))
304 safe_allocate(this%r(1:this%np))
305
306 do ip = 1, this%np
307 order(ip) = ip
308 end do
309
310 ! First we just reorder in order to determine overlap:
311 call sort(this%map, order)
312
313 !check whether points overlap (i.e. whether a submesh contains the same point more than once)
314 this%overlap = .false.
315 do ip = 1, this%np - 1
316 if (this%map(ip) == this%map(ip + 1)) then
317 ! this simplified test works, as the points are ordered.
318 this%overlap = .true.
319 exit
320 end if
321 end do
322
323 this%num_regions = 1
324 call profiling_out("SUBMESH_INIT_ORDER")
325
326 if(this%overlap) then
327 call profiling_in("SUBMESH_INIT_OVERLAP")
328 !disentangle the map into injective regions
329
330 safe_allocate(tmp_array(1:this%np))
331 safe_allocate(order_new(1:this%np))
332 safe_allocate(np_region(1:this%np))
333 safe_allocate(map_new( 1:this%np))
334
335 np_region(1) = 1
336 tmp_array(1) = 1
337 i_region = 1
338
339 do ip = 2, this%np
340 if (this%map(ip) == this%map(ip - 1)) then
341 i_region = i_region + 1
342 if (i_region > this%num_regions) then
343 this%num_regions = i_region
344 np_region(i_region) = 0
345 end if
346 else
347 i_region = 1
348 end if
349 tmp_array(ip) = i_region ! which region does ip belong to
350 np_region(i_region) = np_region(i_region) + 1 ! increase number of points in i_region
351 end do
352
353 assert( .not. allocated(this%regions))
354
355 ! construct array of offsets
356 safe_allocate(this%regions(1:this%num_regions+1))
357
358 this%regions(1) = 1
359
360 if(this%num_regions > 1) then
361 do i_region = 1, this%num_regions
362 this%regions(i_region + 1) = this%regions(i_region) + np_region(i_region)
363 end do
364 else
365 this%regions(2) = this%np + 1
366 end if
367
368 np_region(1:this%np) = 0
369 order_new(1:this%np) = -1
370 map_new(1:this%np) = -1
371
372
373 !reassemble regions into global map array
374 do ip = 1, this%np
375 i_region = tmp_array(ip)
376 np_region(i_region) = np_region(i_region) + 1
377 offset = this%regions(i_region) - 1
378 map_new( offset + np_region(i_region) ) = this%map(ip)
379 order_new( offset + np_region(i_region) ) = order(ip)
380 end do
381
382 order(1:this%np) = order_new(1:this%np)
383 this%map(1:this%np) = map_new(1:this%np)
384
385 safe_deallocate_a(tmp_array)
386 safe_deallocate_a(order_new)
387 safe_deallocate_a(np_region)
388 safe_deallocate_a(map_new)
389 call profiling_out("SUBMESH_INIT_OVERLAP")
390
391 else
392 this%num_regions = 1
393 safe_allocate(this%regions(1:2))
394 this%regions(1) = 1
395 this%regions(2) = this%np + 1
396 end if
397
398 ! Lastly, reorder the points according to the new scheme
399 do ip = 1, this%np
400 this%rel_x(:, ip) = xtmp(:, order(ip))
401 this%r(ip) = rtmp(order(ip))
402 end do
403
404 safe_deallocate_a(order)
405
407 end subroutine submesh_reorder_points
408
409
410 ! --------------------------------------------------------------
411 !This routine takes two submeshes and merge them into a bigger submesh
412 !The grid is centered on the first center
413 subroutine submesh_merge(this, space, mesh, sm1, sm2, shift)
414 type(submesh_t), intent(inout) :: this
415 class(space_t), intent(in) :: space
416 class(mesh_t), target, intent(in) :: mesh
417 type(submesh_t), intent(in) :: sm1
418 type(submesh_t), intent(in) :: sm2
419 real(real64), optional, intent(in) :: shift(:)
420
421 real(real64) :: r2
422 integer :: ip, is
423 real(real64) :: xx(space%dim), diff_centers(space%dim)
424
425 push_sub(submesh_merge)
426 call profiling_in("SUBMESH_MERGE")
427
428 this%mesh => mesh
429
430 safe_allocate(this%center(1:space%dim))
431 this%center(:) = sm1%center(:)
432 this%radius = sm1%radius
433
434 ! This is a quick fix to prevent uninitialized variables. To properly check the self-overlap,
435 ! a similar approach as in submesh_init should be taken with respect to the merged map.
436 this%overlap = sm1%overlap .or. sm2%overlap
437
438 diff_centers = sm1%center - sm2%center
439 if (present(shift)) diff_centers = diff_centers - shift
440
441 !As we take the union of the two submeshes, we know that we have all the points from the first one included.
442 !The extra points from the second submesh are those which are not included in the first one
443 is = sm1%np
444 do ip = 1, sm2%np
445 !sm2%x contains points coordinates defined with respect to sm2%center
446 xx = sm2%rel_x(:, ip) - diff_centers
447 !If the point is not in sm1, we add it
448 if (sum(xx**2) > sm1%radius**2) is = is + 1
449 end do
450
451 this%np = is
452
453 safe_allocate(this%map(1:this%np))
454 safe_allocate(this%rel_x(1:space%dim, 1:this%np))
455 safe_allocate(this%r(1:this%np))
456 this%map(1:sm1%np) = sm1%map(1:sm1%np)
457 this%rel_x(:, 1:sm1%np) = sm1%rel_x(:, 1:sm1%np)
458 this%r(1:sm1%np) = sm1%r(1:sm1%np)
459
460 !iterate again to fill the tables
461 is = sm1%np
462 do ip = 1, sm2%np
463 xx = sm2%rel_x(:, ip) - diff_centers
464 r2 = sum(xx**2)
465 if (r2 > sm1%radius**2) then
466 is = is + 1
467 this%map(is) = sm2%map(ip)
468 this%r(is) = sqrt(r2)
469 this%rel_x(:, is) = xx
470 end if
471 end do
472
473 call profiling_out("SUBMESH_MERGE")
474 pop_sub(submesh_merge)
475 end subroutine submesh_merge
476
477 ! --------------------------------------------------------------
478 !This routine shifts the center of a submesh, without changing the grid points
479 subroutine submesh_shift_center(this, space, newcenter)
480 type(submesh_t), intent(inout) :: this
481 class(space_t), intent(in) :: space
482 real(real64), intent(in) :: newcenter(:)
483
484 real(real64) :: xx(space%dim), diff_centers(space%dim), oldcenter(space%dim)
485 integer :: ip
486
487 push_sub(submesh_shift_center)
488 call profiling_in("SUBMESH_SHIFT")
489
490 oldcenter = this%center
491 this%center(:) = newcenter(:)
492
493 diff_centers = newcenter - oldcenter
494
495 do ip = 1, this%np
496 xx = this%rel_x(:, ip) - diff_centers
497 this%r(ip) = norm2(xx)
498 this%rel_x(:, ip) = xx
499 end do
500
501 call profiling_out("SUBMESH_SHIFT")
502 pop_sub(submesh_shift_center)
503 end subroutine submesh_shift_center
504
505 ! --------------------------------------------------------------
506 subroutine submesh_broadcast(this, space, mesh, center, radius, root, mpi_grp)
507 type(submesh_t), intent(inout) :: this
508 class(space_t), intent(in) :: space
509 type(mesh_t), target, intent(in) :: mesh
510 real(real64), intent(in) :: center(1:space%dim)
511 real(real64), intent(in) :: radius
512 integer, intent(in) :: root
513 type(mpi_grp_t), intent(in) :: mpi_grp
514
515 integer :: nparray(1:3)
516
517 push_sub(submesh_broadcast)
518 call profiling_in('SUBMESH_BCAST')
519
520 if (root /= mpi_grp%rank) then
521 this%mesh => mesh
522 safe_allocate(this%center(1:space%dim))
523 this%center(:) = center(:)
524 this%radius = radius
525 end if
526
527 if (mpi_grp%size > 1) then
528
529 if (root == mpi_grp%rank) then
530 nparray(1) = this%np
531 nparray(2) = this%num_regions
532 if (this%overlap) then
533 nparray(3) = 1
534 else
535 nparray(3) = 0
536 end if
537 end if
538
539 call mpi_grp%bcast(nparray, 3, mpi_integer, root)
540 this%np = nparray(1)
541 this%num_regions = nparray(2)
542 this%overlap = (nparray(3) == 1)
543
544 if (root /= mpi_grp%rank) then
545 safe_allocate(this%map(1:this%np))
546 safe_allocate(this%rel_x(1:space%dim, 1:this%np))
547 safe_allocate(this%r(1:this%np))
548 safe_allocate(this%regions(1:this%num_regions+1))
549 end if
550
551 call mpi_grp%bcast(this%regions(1), this%num_regions+1, mpi_integer, root)
552
553 if (this%np > 0) then
554 call mpi_grp%bcast(this%map(1), this%np, mpi_integer, root)
555 call mpi_grp%bcast(this%rel_x(1, 1), this%np*space%dim, mpi_double_precision, root)
556 call mpi_grp%bcast(this%r(1), this%np, mpi_double_precision, root)
557 end if
558
559 end if
560
561 call profiling_out('SUBMESH_BCAST')
562 pop_sub(submesh_broadcast)
563 end subroutine submesh_broadcast
564
565 ! --------------------------------------------------------------
566 logical function submesh_compatible(this, radius, center, dx) result(compatible)
567 type(submesh_t), intent(in) :: this
568 real(real64), intent(in) :: radius
569 real(real64), intent(in) :: center(:)
570 real(real64), intent(in) :: dx
571
572 compatible =.false.
573 if (allocated(this%center)) then
576 if (radius <= this%radius+dx*1e-6_real64 .and. all(abs(this%center - center) < 0.25*dx)) then
577 compatible = .true.
578 end if
579 end if
580
581 end function submesh_compatible
582
583 ! --------------------------------------------------------------
584 subroutine submesh_end(this)
585 type(submesh_t), intent(inout) :: this
586
587 push_sub(submesh_end)
588
589 nullify(this%mesh)
590 nullify(this%box)
591 if (this%np /= -1) then
592 this%np = -1
593 safe_deallocate_a(this%center)
594 safe_deallocate_a(this%map)
595 safe_deallocate_a(this%rel_x)
596 safe_deallocate_a(this%r)
597 safe_deallocate_a(this%regions)
598 end if
599
600 if (accel_is_enabled()) then
601 call accel_free_buffer(this%buff_map)
602 end if
603
604 pop_sub(submesh_end)
605 end subroutine submesh_end
606
607
608 ! --------------------------------------------------------------
609 logical function submesh_overlap(sm1, sm2, space) result(overlap)
610 type(submesh_t), intent(in) :: sm1
611 type(submesh_t), intent(in) :: sm2
612 class(space_t), intent(in) :: space
613
614 integer :: ii, jj, dd
615 real(real64) :: distance
616
617 !no PUSH_SUB, called too often
618
619 if (.not. space%is_periodic()) then
620 !first check the distance
621 distance = sum((sm1%center - sm2%center)**2)
622 overlap = distance <= (1.5_real64*(sm1%radius + sm2%radius))**2
623
624 ! if they are very far, no need to check in detail
625 if (.not. overlap) return
626 end if
627
628 ! Otherwise check whether they have the some point in common. We
629 ! can make the comparison faster using that the arrays are sorted.
630 overlap = .false.
631 ii = 1
632 jj = 1
633 do while(ii <= sm1%np .and. jj <= sm2%np)
634 dd = sm1%map(ii) - sm2%map(jj)
635 if (dd < 0) then
636 ii = ii + 1
637 else if (dd > 0) then
638 jj = jj + 1
639 else
640 overlap = .true.
641 exit
642 end if
643 end do
644
645 if (sm1%mesh%parallel_in_domains) then
646 call sm1%mesh%mpi_grp%allreduce_inplace(overlap, 1, mpi_logical, mpi_lor)
647 end if
648
649 end function submesh_overlap
650
651 ! -------------------------------------------------------------
652 subroutine submesh_build_global(this, space)
653 type(submesh_t), intent(inout) :: this
654 class(space_t), intent(in) :: space
655
656 integer, allocatable :: part_np(:)
657 integer :: ipart, ind, ip
658
659 push_sub(submesh_build_global)
660
661 if (.not. this%mesh%parallel_in_domains) then
662 this%np_global = this%np
663 pop_sub(submesh_build_global)
664 return
665 end if
666
667 safe_allocate(part_np(this%mesh%pv%npart))
668 part_np = 0
669 part_np(this%mesh%pv%partno) = this%np
670
671 call this%mesh%allreduce(part_np)
672 this%np_global = sum(part_np)
673
674 safe_allocate(this%rel_x_global(1:space%dim, 1:this%np_global))
675 safe_allocate(this%part_v(1:this%np_global))
676 safe_allocate(this%global2local(1:this%np_global))
677 this%rel_x_global(1:space%dim, 1:this%np_global) = m_zero
678 this%part_v(1:this%np_global) = 0
679 this%global2local(1:this%np_global) = 0
680
681 ind = 0
682 do ipart = 1, this%mesh%pv%npart
683 if (ipart == this%mesh%pv%partno) then
684 do ip = 1, this%np
685 this%rel_x_global(:, ind + ip) = this%rel_x(:, ip)
686 this%part_v(ind + ip) = this%mesh%pv%partno
687 this%global2local(ind + ip) = ip
688 end do
689 end if
690 ind = ind + part_np(ipart)
691 end do
692
693 call this%mesh%allreduce(this%rel_x_global)
694 call this%mesh%allreduce(this%part_v)
695 call this%mesh%allreduce(this%global2local)
696
697 safe_deallocate_a(part_np)
698
699 pop_sub(submesh_build_global)
700 end subroutine submesh_build_global
701
702 ! -----------------------------------------------------------
703 subroutine submesh_end_global(this)
704 type(submesh_t), intent(inout) :: this
705
706 push_sub(submesh_end_global)
707
708 safe_deallocate_a(this%rel_x_global)
709 this%np_global = -1
710 safe_deallocate_a(this%part_v)
711 safe_deallocate_a(this%global2local)
712
713 pop_sub(submesh_end_global)
714 end subroutine submesh_end_global
715
716
717 ! -----------------------------------------------------------
718 subroutine zzsubmesh_add_to_mesh(this, sphi, phi, factor)
719 type(submesh_t), intent(in) :: this
720 complex(real64), intent(in) :: sphi(:)
721 complex(real64), intent(inout) :: phi(:)
722 complex(real64), optional, intent(in) :: factor
723
724 integer :: ip, m
725
726 push_sub(zzsubmesh_add_to_mesh)
727
728 if (present(factor)) then
729 !Loop unrolling inspired by BLAS axpy routine
730 m = mod(this%np,4)
731 do ip = 1, m
732 phi(this%map(ip)) = phi(this%map(ip)) + factor*sphi(ip)
733 end do
734 if (this%np.ge.4) then
735 do ip = m+1, this%np, 4
736 phi(this%map(ip)) = phi(this%map(ip)) + factor*sphi(ip)
737 phi(this%map(ip+1)) = phi(this%map(ip+1)) + factor*sphi(ip+1)
738 phi(this%map(ip+2)) = phi(this%map(ip+2)) + factor*sphi(ip+2)
739 phi(this%map(ip+3)) = phi(this%map(ip+3)) + factor*sphi(ip+3)
740 end do
741 end if
742 else
743 m = mod(this%np,4)
744 do ip = 1, m
745 phi(this%map(ip)) = phi(this%map(ip)) + sphi(ip)
746 end do
747 if (this%np.ge.4) then
748 do ip = m+1, this%np, 4
749 phi(this%map(ip)) = phi(this%map(ip)) + sphi(ip)
750 phi(this%map(ip+1)) = phi(this%map(ip+1)) + sphi(ip+1)
751 phi(this%map(ip+2)) = phi(this%map(ip+2)) + sphi(ip+2)
752 phi(this%map(ip+3)) = phi(this%map(ip+3)) + sphi(ip+3)
753 end do
754 end if
755 end if
756
757 pop_sub(zzsubmesh_add_to_mesh)
758 end subroutine zzsubmesh_add_to_mesh
759
760 !------------------------------------------------------------
761 complex(real64) function zzsubmesh_to_mesh_dotp(this, sphi, phi, reduce) result(dotp)
762 type(submesh_t), intent(in) :: this
763 complex(real64), intent(in) :: sphi(:)
764 complex(real64), intent(in) :: phi(:)
765 logical, optional, intent(in) :: reduce
766
767 integer :: is, m, ip
768
769 push_sub(zzsubmesh_to_mesh_dotp)
770
771 dotp = m_z0
772
773 if (this%mesh%use_curvilinear) then
774 do is = 1, this%np
775 dotp = dotp + this%mesh%vol_pp(this%map(is))*phi(this%map(is))*conjg(sphi(is))
776 end do
777 else
778 m = mod(this%np,4)
779 do ip = 1, m
780 dotp = dotp + phi(this%map(ip))*conjg(sphi(ip))
781 end do
782 if (this%np.ge.4) then
783 do ip = m+1, this%np, 4
784 dotp = dotp + phi(this%map(ip))*conjg(sphi(ip)) &
785 + phi(this%map(ip+1))*conjg(sphi(ip+1)) &
786 + phi(this%map(ip+2))*conjg(sphi(ip+2)) &
787 + phi(this%map(ip+3))*conjg(sphi(ip+3))
788 end do
789 end if
790 dotp = dotp*this%mesh%vol_pp(1)
791 end if
792
793 if (optional_default(reduce, .true.)) then
794 call profiling_in("SM_REDUCE_DOTP")
795 call this%mesh%allreduce(dotp)
796 call profiling_out("SM_REDUCE_DOTP")
797 end if
800 end function zzsubmesh_to_mesh_dotp
801
802 !------------------------------------------------------------
804 subroutine submesh_get_cube_dim(sm, space, db)
805 type(submesh_t), target, intent(in) :: sm
806 class(space_t), intent(in) :: space
807 integer, intent(out) :: db(1:space%dim)
808
809 integer :: ip, idir
810 real(real64) :: chi(space%dim), max_chi(space%dim)
811 integer :: db_red(1:space%dim)
812 real(real64), parameter :: tol=1.0e-10_real64
814 push_sub(submesh_get_cube_dim)
815
816 max_chi = m_zero
817 do ip = 1, sm%np
818 chi = sm%mesh%coord_system%from_cartesian(sm%rel_x(:, ip))
819 do idir = 1, space%dim
820 max_chi(idir) = max(max_chi(idir), abs(chi(idir))/sm%mesh%spacing(idir))
821 end do
822 end do
823
824 do idir = 1, space%dim
825 db(idir) = nint(max_chi(idir)-tol)
826 end do
827
828 if(sm%mesh%parallel_in_domains) then
829 call sm%mesh%mpi_grp%allreduce(db(1), db_red(1), space%dim, mpi_integer, mpi_max)
830 db(1:space%dim) = db_red(1:space%dim)
831 end if
832
833 db = 2 * db + 1
834
835 pop_sub(submesh_get_cube_dim)
836 end subroutine submesh_get_cube_dim
837
838 !------------------------------------------------------------
839 subroutine submesh_init_cube_map(sm, space)
840 type(submesh_t), target, intent(inout) :: sm
841 class(space_t), intent(in) :: space
842
843 integer(int64) :: ip
844 integer ::idir
845 real(real64) :: chi(space%dim), shift(space%dim)
846
847 push_sub(submesh_init_cube_map)
848
849 sm%cube_map%nmap = sm%np
850
851 safe_allocate(sm%cube_map%map(1:space%dim, 1:sm%cube_map%nmap))
852
853 !The center of the submesh does not belong to the mesh
854 !So we first need to find the closest grid point, and center the cube to it
855 chi = sm%mesh%coord_system%from_cartesian(sm%center)
856 do idir = 1, space%dim
857 shift(idir) = nint(chi(idir)/sm%mesh%spacing(idir))*sm%mesh%spacing(idir)
858 end do
859 shift = sm%mesh%coord_system%to_cartesian(shift)
860 shift = shift - sm%center
861
862 do ip = 1, sm%cube_map%nmap
863 chi = sm%mesh%coord_system%from_cartesian(sm%rel_x(:,ip) - shift)
864 do idir = 1, space%dim
865 sm%cube_map%map(idir, ip) = nint(chi(idir)/sm%mesh%spacing(idir))
866 end do
867 end do
868
869 if (accel_is_enabled()) then
870 call accel_create_buffer(sm%cube_map%map_buffer, accel_mem_read_only, type_integer, sm%cube_map%nmap*space%dim)
871 call accel_write_buffer(sm%cube_map%map_buffer, space%dim, sm%cube_map%nmap, sm%cube_map%map)
872 end if
873
874 pop_sub(submesh_init_cube_map)
875 end subroutine submesh_init_cube_map
876
877 !------------------------------------------------------------
878 subroutine submesh_end_cube_map(sm)
879 type(submesh_t), intent(inout) :: sm
880
881 push_sub(submesh_end_cube_map)
882
883 call mesh_cube_map_end(sm%cube_map)
884
885 pop_sub(submesh_end_cube_map)
886 end subroutine submesh_end_cube_map
887
894 subroutine dzsubmesh_batch_add(this, ss, mm)
895 type(submesh_t), intent(in) :: this
896 class(batch_t), intent(in) :: ss
897 class(batch_t), intent(inout) :: mm
898
899 integer :: ist, idim, jdim, is
900
901 push_sub(dzsubmesh_batch_add)
902
903 assert(.not. mm%is_packed())
904 assert(ss%type() == type_float)
905 assert(mm%type() == type_cmplx)
906 assert(ss%nst_linear == mm%nst_linear)
907 assert(ss%status() == mm%status())
908 assert(ss%dim == mm%dim)
909
910 assert(mm%nst == ss%nst)
911
912 !$omp parallel do private(ist, idim, jdim, is) if(.not. this%overlap)
913 do ist = 1, mm%nst
914 do idim = 1, mm%dim
915 jdim = min(idim, ss%dim)
916
917 do is = 1, this%np
918 mm%zff(this%map(is), idim, ist) = &
919 mm%zff(this%map(is), idim, ist) + ss%dff(is, jdim, ist)
920 end do
921
922 end do
923 end do
924 !$omp end parallel do
925
926 pop_sub(dzsubmesh_batch_add)
927 end subroutine dzsubmesh_batch_add
928
929
930#include "undef.F90"
931#include "real.F90"
932#include "submesh_inc.F90"
933
934#include "undef.F90"
935#include "complex.F90"
936#include "submesh_inc.F90"
937
938end module submesh_oct_m
939
940!! Local Variables:
941!! mode: f90
942!! coding: utf-8
943!! 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:939
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:1139
subroutine zdsubmesh_add_to_mesh(this, sphi, phi, factor)
Definition: submesh.F90:1738
subroutine, public submesh_init_cube_map(sm, space)
Definition: submesh.F90:935
logical function, public submesh_overlap(sm1, sm2, space)
Definition: submesh.F90:705
subroutine, public zsubmesh_batch_dotp_matrix(this, mm, ss, dot, reduce)
Definition: submesh.F90:2043
real(real64) function, public dsm_nrm2(sm, ff, reduce)
this function returns the the norm of a vector
Definition: submesh.F90:1262
subroutine zzsubmesh_add_to_mesh(this, sphi, phi, factor)
Definition: submesh.F90:814
subroutine, public submesh_end_global(this)
Definition: submesh.F90:799
subroutine, public zsubmesh_copy_from_mesh(this, phi, sphi, conjugate)
Definition: submesh.F90:1786
subroutine submesh_reorder_points(this, space, xtmp, rtmp)
Definition: submesh.F90:383
complex(real64) function, public zsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1648
subroutine, public submesh_shift_center(this, space, newcenter)
Definition: submesh.F90:575
complex(real64) function zzsubmesh_to_mesh_dotp(this, sphi, phi, reduce)
Definition: submesh.F90:857
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1094
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:1344
recursive real(real64) function f_n(dims)
Definition: submesh.F90:212
subroutine, public dsubmesh_copy_from_mesh(this, phi, sphi, conjugate)
Definition: submesh.F90:1232
real(real64) function ddsubmesh_to_mesh_dotp(this, sphi, phi, reduce)
Definition: submesh.F90:1299
subroutine, public submesh_merge(this, space, mesh, sm1, sm2, shift)
Definition: submesh.F90:509
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:990
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:1991
real(real64) function, public zsm_nrm2(sm, ff, reduce)
this function returns the the norm of a vector
Definition: submesh.F90:1816
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:1898
subroutine, public submesh_end_cube_map(sm)
Definition: submesh.F90:974
subroutine, public submesh_end(this)
Definition: submesh.F90:680
subroutine ddsubmesh_add_to_mesh(this, sphi, phi, factor)
Definition: submesh.F90:1184
subroutine, public submesh_get_cube_dim(sm, space, db)
finds the dimension of a box containing the submesh
Definition: submesh.F90:900
subroutine, public dsubmesh_batch_dotp_matrix(this, mm, ss, dot, reduce)
Definition: submesh.F90:1489
complex(real64) function, public zsm_integrate_frommesh(mesh, sm, ff, reduce)
Definition: submesh.F90:1693
logical function, public submesh_compatible(this, radius, center, dx)
Definition: submesh.F90:662
subroutine, public submesh_build_global(this, space)
Definition: submesh.F90:748
subroutine, public submesh_broadcast(this, space, mesh, center, radius, root, mpi_grp)
Definition: submesh.F90:602
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:1437
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:1853
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