Octopus
mesh.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2011 M. Marques, A. Castro, A. Rubio, G. Bertsch, M. Oliveira
2!! Copyright (C) 2021 S. Ohlmann
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
24
25module mesh_oct_m
26 use accel_oct_m
28 use box_oct_m
29 use comm_oct_m
31 use debug_oct_m
32 use global_oct_m
33 use iihash_oct_m
34 use index_oct_m
35 use io_oct_m
38 use mpi_oct_m
43 use parser_oct_m
45 use space_oct_m
48 use unit_oct_m
50
51 implicit none
52
53 private
54 public :: &
55 mesh_t, &
59 mesh_end, &
61 mesh_r, &
81
93 type, extends(basis_set_abst_t) :: mesh_t
94 ! Components are public by default
95 class(box_t), pointer :: box
96 class(coordinate_system_t), pointer :: coord_system
97 type(index_t) :: idx
98 logical :: use_curvilinear
99 logical :: use_vol_pp = .false.
100
101 real(real64), allocatable :: spacing(:)
102
103 ! When running serially, the local number of points is
104 ! equal to the global number of points.
105 ! Otherwise, the next two are different on each node.
106 integer :: np
107 integer :: np_part
108 integer(int64) :: np_global
109 integer(int64) :: np_part_global
110 logical :: parallel_in_domains
111 type(mpi_grp_t) :: mpi_grp
112 type(par_vec_t) :: pv
113 type(partition_t) :: partition
114
115 real(real64), allocatable :: x(:,:)
116 real(real64), allocatable :: x_t(:,:)
117 real(real64), allocatable :: chi(:,:)
118 real(real64) :: volume_element
119 real(real64), allocatable :: vol_pp(:)
120 type(accel_mem_t) :: vol_pp_buffer
121 type(accel_mem_t) :: sqrt_vol_pp_buffer
122 real(real64), allocatable :: jacobian_inverse(:,:,:)
123
124 logical :: masked_periodic_boundaries
125 character(len=256) :: periodic_boundary_mask
127 contains
128 procedure :: end => mesh_end
129 procedure :: init => mesh_init
130 procedure :: write_info => mesh_write_info
131 procedure :: dmesh_allreduce_0, zmesh_allreduce_0, imesh_allreduce_0, lmesh_allreduce_0
132 procedure :: dmesh_allreduce_1, zmesh_allreduce_1, imesh_allreduce_1, lmesh_allreduce_1
133 procedure :: dmesh_allreduce_2, zmesh_allreduce_2, imesh_allreduce_2, lmesh_allreduce_2
134 procedure :: dmesh_allreduce_3, zmesh_allreduce_3, imesh_allreduce_3, lmesh_allreduce_3
135 procedure :: dmesh_allreduce_4, zmesh_allreduce_4, imesh_allreduce_4, lmesh_allreduce_4
136 procedure :: dmesh_allreduce_5, zmesh_allreduce_5, imesh_allreduce_5, lmesh_allreduce_5
137 procedure :: dmesh_allreduce_6, zmesh_allreduce_6, imesh_allreduce_6, lmesh_allreduce_6
138 generic :: allreduce => dmesh_allreduce_0, zmesh_allreduce_0, imesh_allreduce_0, lmesh_allreduce_0
139 generic :: allreduce => dmesh_allreduce_1, zmesh_allreduce_1, imesh_allreduce_1, lmesh_allreduce_1
140 generic :: allreduce => dmesh_allreduce_2, zmesh_allreduce_2, imesh_allreduce_2, lmesh_allreduce_2
141 generic :: allreduce => dmesh_allreduce_3, zmesh_allreduce_3, imesh_allreduce_3, lmesh_allreduce_3
142 generic :: allreduce => dmesh_allreduce_4, zmesh_allreduce_4, imesh_allreduce_4, lmesh_allreduce_4
143 generic :: allreduce => dmesh_allreduce_5, zmesh_allreduce_5, imesh_allreduce_5, lmesh_allreduce_5
144 generic :: allreduce => dmesh_allreduce_6, zmesh_allreduce_6, imesh_allreduce_6, lmesh_allreduce_6
145 procedure :: red_min => mesh_red_min
146 end type mesh_t
147
159 type mesh_plane_t
160 ! Components are public by default
161 real(real64) :: n(3)
162 real(real64) :: u(3), v(3)
163 real(real64) :: origin(3)
164 real(real64) :: spacing
165 integer :: nu, mu, nv, mv
166 end type mesh_plane_t
167
171 type mesh_line_t
172 ! Components are public by default
173 real(real64) :: n(2)
174 real(real64) :: u(2)
175 real(real64) :: origin(2)
176 real(real64) :: spacing
177 integer :: nu, mu
178 end type mesh_line_t
179
180contains
181
182 subroutine mesh_init(this)
183 class(mesh_t), intent(inout) :: this
184
185 push_sub(mesh_init)
186
187 call this%set_time_dependent(.false.)
189 pop_sub(mesh_init)
190 end subroutine mesh_init
192! ---------------------------------------------------------
194 subroutine mesh_double_box(space, mesh, alpha, db)
195 class(space_t), intent(in) :: space
196 type(mesh_t), intent(in) :: mesh
197 real(real64), intent(in) :: alpha
198 integer, contiguous, intent(out) :: db(:)
199
200 integer :: idir
204 db = 1
206 ! double mesh with 2n points
207 do idir = 1, space%periodic_dim
208 db(idir) = mesh%idx%ll(idir)
209 end do
210 do idir = space%periodic_dim + 1, space%dim
211 db(idir) = nint(alpha * (mesh%idx%ll(idir) - 1)) + 1
212 end do
215 end subroutine mesh_double_box
218 ! ---------------------------------------------------------
219 subroutine mesh_write_info(this, iunit, namespace)
220 class(mesh_t), intent(in) :: this
221 integer, optional, intent(in) :: iunit
222 type(namespace_t), optional, intent(in) :: namespace
224 integer :: ii
225 real(real64) :: cutoff
229 write(message(1),'(3a)') ' Spacing [', trim(units_abbrev(units_out%length)), '] = ('
230 do ii = 1, this%box%dim
231 if (ii > 1) write(message(1), '(2a)') trim(message(1)), ','
232 write(message(1), '(a,f6.3)') trim(message(1)), units_from_atomic(units_out%length, this%spacing(ii))
233 end do
234 write(message(1), '(5a,f12.5)') trim(message(1)), ') ', &
235 ' volume/point [', trim(units_abbrev(units_out%length**this%box%dim)), '] = ', &
236 units_from_atomic(units_out%length**this%box%dim, this%vol_pp(1))
238 write(message(2),'(a, i10)') ' # inner mesh = ', this%np_global
239 write(message(3),'(a, i10)') ' # total mesh = ', this%np_part_global
241 cutoff = mesh_gcutoff(this)**2 / m_two
242 write(message(4),'(3a,f12.6,a,f12.6)') ' Grid Cutoff [', trim(units_abbrev(units_out%energy)),'] = ', &
243 units_from_atomic(units_out%energy, cutoff), ' Grid Cutoff [Ry] = ', cutoff * m_two
244 call messages_info(4, iunit=iunit, namespace=namespace)
245
246 pop_sub(mesh_write_info)
247 end subroutine mesh_write_info
248
249
251 pure subroutine mesh_r(mesh, ip, rr, origin, coords)
252 class(mesh_t), intent(in) :: mesh
253 integer, intent(in) :: ip
254 real(real64), intent(out) :: rr
255 real(real64), intent(in), optional :: origin(:)
256 real(real64), intent(out), optional :: coords(:)
258 real(real64) :: xx(1:mesh%box%dim)
260 xx = mesh%x(:, ip)
261 if (present(origin)) xx = xx - origin
262 rr = norm2(xx)
263
264 if (present(coords)) then
265 coords = xx
266 end if
267
268 end subroutine mesh_r
271 subroutine mesh_r_global(mesh, ipg, rr, origin, coords)
272 class(mesh_t), intent(in) :: mesh
273 integer(int64),intent(in) :: ipg
274 real(real64), intent(out) :: rr
275 real(real64), contiguous, intent(in), optional :: origin(:)
276 real(real64), contiguous, intent(out), optional :: coords(:)
278 real(real64) :: xx(1:mesh%box%dim)
279
280 xx = mesh_x_global(mesh, ipg)
281 if (present(origin)) xx = xx - origin
282 rr = norm2(xx)
283
284 if (present(coords)) then
285 coords = xx
286 end if
287
288 end subroutine mesh_r_global
290
295 integer function mesh_nearest_point(mesh, pos, dmin, rankmin) result(ind)
296 class(mesh_t),intent(in) :: mesh
297 real(real64), intent(in) :: pos(:)
298 real(real64), intent(out) :: dmin
299 integer, intent(out) :: rankmin
300 ! This returns 0 in the absence of domain decomposition
301
302 real(real64) :: dd
303 integer :: imin, ip
304
305 push_sub(mesh_nearest_point)
306
307 ! find the point of the grid that is closer to the atom
308 dmin = m_zero
309 do ip = 1, mesh%np
310 dd = sum((pos - mesh%x(:, ip))**2)
311 if ((dd < dmin) .or. (ip == 1)) then
312 imin = ip
313 dmin = dd
314 end if
315 end do
316
317 call mesh_minmaxloc(mesh, dmin, rankmin, mpi_minloc)
318 call mesh%mpi_grp%bcast(imin, 1, mpi_integer, rankmin)
319
320 ind = imin
321 pop_sub(mesh_nearest_point)
322 end function mesh_nearest_point
323
325 subroutine mesh_discretize_values_to_mesh(mesh, values)
326 class(mesh_t), intent(in ) :: mesh
327 real(real64), contiguous, intent(inout) :: values(:, :)
328 ! Out: Values discretized to mesh points
329 integer :: i, ip, ndim
330 integer :: process
331 real(real64) :: dummy
332
334
335 if (mesh%parallel_in_domains) then
336 ndim = size(values, 1)
337 do i = 1, size(values, 2)
338 ip = mesh_nearest_point(mesh, values(:, i), dummy, process)
339 ! ip is defined for `process`, only
340 if (mesh%mpi_grp%rank == process) values(:, i) = mesh%x(:, ip)
341 call mesh%mpi_grp%bcast(values(:, i), ndim, mpi_double_precision, process)
342 enddo
343 else
344 do i = 1, size(values, 2)
345 ip = mesh_nearest_point(mesh, values(:, i), dummy, process)
346 values(:, i) = mesh%x(:, ip)
347 enddo
348 endif
349
351
352 end subroutine mesh_discretize_values_to_mesh
353
354 ! --------------------------------------------------------------
358 ! --------------------------------------------------------------
359 real(real64) function mesh_gcutoff(mesh) result(gmax)
360 class(mesh_t), intent(in) :: mesh
361
362 push_sub(mesh_gcutoff)
363 gmax = m_pi / (maxval(mesh%spacing))
364
365 pop_sub(mesh_gcutoff)
366 end function mesh_gcutoff
367
368 ! --------------------------------------------------------------
369 subroutine mesh_write_fingerprint(mesh, dir, filename, mpi_grp, namespace, ierr)
370 type(mesh_t), intent(in) :: mesh
371 character(len=*), intent(in) :: dir
372 character(len=*), intent(in) :: filename
373 type(mpi_grp_t), intent(in) :: mpi_grp
374 type(namespace_t),intent(in) :: namespace
375 integer, intent(out) :: ierr
376
377 integer :: iunit, ii
378
379 push_sub(mesh_write_fingerprint)
380
381 ierr = 0
382
383 iunit = io_open(trim(dir)//"/"//trim(filename), namespace, action='write', &
384 die=.false., grp=mpi_grp)
385 if (iunit == -1) then
386 message(1) = "Unable to open file '"//trim(dir)//"/"//trim(filename)//"'."
387 call messages_warning(1, namespace=namespace)
388 ierr = ierr + 1
389 else
390 if (mpi_grp%is_root()) then
391 write(iunit, '(a20,i21)') 'np_part_global= ', mesh%np_part_global
392 write(iunit, '(a20,i21)') 'np_global= ', mesh%np_global
393 write(iunit, '(a20,i21)') 'algorithm= ', 1
394 write(iunit, '(a20,i21)') 'checksum= ', mesh%idx%checksum
395 write(iunit, '(a20,i21)') 'bits= ', mesh%idx%bits
396 write(iunit, '(a20,i21)') 'dim= ', mesh%idx%dim
397 write(iunit, '(a20,i21)') 'type= ', mesh%idx%type
398 do ii = 1, mesh%idx%dim
399 write(iunit, '(a7,i2,a11,i21)') 'offset(',ii,')= ', mesh%idx%offset(ii)
400 end do
401 do ii = 1, mesh%idx%dim
402 write(iunit, '(a7,i2,a11,i21)') 'nn(',ii,')= ', mesh%idx%nr(2, ii) - mesh%idx%nr(1, ii) + 1
403 end do
404 end if
405 call io_close(iunit, grp=mpi_grp)
406 end if
407
409 end subroutine mesh_write_fingerprint
410
411
412 ! -----------------------------------------------------------------------
417 subroutine mesh_read_fingerprint(mesh, dir, filename, mpi_grp, namespace, &
418 read_np_part, read_np, bits, type, offset, nn, ierr)
419 type(mesh_t), intent(in) :: mesh
420 character(len=*), intent(in) :: dir
421 character(len=*), intent(in) :: filename
422 type(mpi_grp_t), intent(in) :: mpi_grp
423 type(namespace_t),intent(in) :: namespace
424 integer(int64), intent(out) :: read_np_part
425 integer(int64), intent(out) :: read_np
426 integer, intent(out) :: bits
427 integer, intent(out) :: type
428 integer, intent(out) :: offset(1:mesh%idx%dim)
429 integer, intent(out) :: nn(1:mesh%idx%dim)
430 integer, intent(out) :: ierr
431
432 character(len=20) :: str
433 character(len=100) :: lines(7)
434 integer :: iunit, algorithm, dim, err, ii
435 integer(int64) :: checksum
436
437 push_sub(mesh_read_fingerprint)
438
439 ierr = 0
440
441 read_np_part = 0_int64
442 read_np = 0_int64
443
444 iunit = io_open(trim(dir)//"/"//trim(filename), namespace, action='read', &
445 status='old', die=.false., grp=mpi_grp)
446 if (iunit == -1) then
447 ierr = ierr + 1
448 message(1) = "Unable to open file '"//trim(dir)//"/"//trim(filename)//"'."
449 call messages_warning(1, namespace=namespace)
450 else
451 call iopar_read(mpi_grp, iunit, lines, 7, err)
452 if (err /= 0) then
453 ierr = ierr + 4
454 else
455 read(lines(1), '(a20,i21)') str, read_np_part
456 read(lines(2), '(a20,i21)') str, read_np
457 read(lines(3), '(a20,i21)') str, algorithm
458 read(lines(4), '(a20,i21)') str, checksum
459 read(lines(5), '(a20,i21)') str, bits
460 read(lines(6), '(a20,i21)') str, dim
461 read(lines(7), '(a20,i21)') str, type
462 ! only allow restarting simulations with the same dimensions
463 if (dim /= mesh%idx%dim) then
464 ierr = ierr + 8
465 else
466 ! read offset, has dim lines
467 call iopar_read(mpi_grp, iunit, lines, dim, err)
468 if (err /= 0) then
469 ierr = ierr + 4
470 else
471 do ii = 1, dim
472 read(lines(ii), '(a20,i21)') str, offset(ii)
473 end do
474 end if
475
476 ! read nn, has dim lines
477 call iopar_read(mpi_grp, iunit, lines, dim, err)
478 if (err /= 0) then
479 ierr = ierr + 4
480 else
481 do ii = 1, dim
482 read(lines(ii), '(a20,i21)') str, nn(ii)
483 end do
484 end if
485 end if
486
487 assert(read_np_part >= read_np)
488
489 if (read_np_part == mesh%np_part_global &
490 .and. read_np == mesh%np_global &
491 .and. algorithm == 1 &
492 .and. checksum == mesh%idx%checksum) then
493 read_np_part = 0
494 read_np = 0
495 end if
496 end if
497
498 call io_close(iunit, grp=mpi_grp)
499 end if
500
501 pop_sub(mesh_read_fingerprint)
502 end subroutine mesh_read_fingerprint
503
504 ! ---------------------------------------------------------
505 subroutine mesh_check_dump_compatibility(mesh, dir, filename, namespace, mpi_grp, grid_changed, grid_reordered, map, ierr)
506 type(mesh_t), intent(in) :: mesh
507 character(len=*), intent(in) :: dir
508 character(len=*), intent(in) :: filename
509 type(namespace_t), intent(in) :: namespace
510 type(mpi_grp_t), intent(in) :: mpi_grp
511 logical, intent(out) :: grid_changed
512 logical, intent(out) :: grid_reordered
513 integer(int64), allocatable, intent(out) :: map(:)
514 integer, intent(out) :: ierr
515
516 integer(int64) :: ipg, ipg_new, read_np_part, read_np
517 integer :: err, idir
518 integer :: bits, type, offset(mesh%idx%dim), point(mesh%idx%dim), nn(mesh%idx%dim)
519 integer(int64), allocatable :: read_indices(:)
520 type(index_t) :: idx_old
521
523
524 ierr = 0
525
526 grid_changed = .false.
527 grid_reordered = .false.
528
529 ! Read the mesh fingerprint
530 call mesh_read_fingerprint(mesh, dir, filename, mpi_grp, namespace, read_np_part, read_np, &
531 bits, type, offset, nn, err)
532 if (err /= 0) then
533 ierr = 1
534 message(1) = "Unable to read mesh fingerprint from '"//trim(dir)//"/"//trim(filename)//"'."
535 call messages_warning(1, namespace=namespace)
536
537 else if (read_np > 0) then
538 if (.not. associated(mesh%box)) then
539 ! We can only check the compatibility of two meshes that have different fingerprints if we also
540 ! have the simulation box. In the case we do not, we will assume that the fingerprint is enough.
541 ierr = ierr + 2
542 else
543 grid_changed = .true.
544
545 ! perhaps only the order of the points changed, this can only
546 ! happen if the number of points is the same and no points maps
547 ! to zero (this is checked below)
548 grid_reordered = (read_np == mesh%np_global)
549
550 ! the grid is different, so we read the coordinates.
551 safe_allocate(read_indices(1:read_np_part))
552 call io_binary_read(trim(io_workpath(dir, namespace))//"/indices.obf", read_np_part, &
553 read_indices, err)
554 if (err /= 0) then
555 ierr = ierr + 4
556 message(1) = "Unable to read index map from '"//trim(dir)//"'."
557 call messages_warning(1, namespace=namespace)
558 else
559 ! dummy index object
560 call index_init(idx_old, mesh%idx%dim)
561 idx_old%type = type
562 idx_old%bits = bits
563 idx_old%nr(1, :) = -offset
564 idx_old%nr(2, :) = -offset + nn - 1
565 idx_old%offset = offset
566 idx_old%stride(1) = 1
567 do idir = 2, mesh%idx%dim
568 idx_old%stride(idir) = idx_old%stride(idir-1) * nn(idir-1)
569 end do
570 ! generate the map
571 safe_allocate(map(1:read_np))
572 do ipg = 1, read_np
573 ! get nd-index from old 1d index
574 call index_spatial_to_point(idx_old, mesh%idx%dim, read_indices(ipg), point)
575 ! get new global index
576 ipg_new = mesh_global_index_from_coords(mesh, point)
577 map(ipg) = ipg_new
578 ! ignore boundary points
579 if (map(ipg) > mesh%np_global) map(ipg) = 0
580 ! if the map is zero for one point, it is not a simple reordering
581 if (map(ipg) == 0) grid_reordered = .false.
582 end do
583 call index_end(idx_old)
584 end if
585
586 safe_deallocate_a(read_indices)
587 end if
588 end if
589
591 end subroutine mesh_check_dump_compatibility
592
593
594 ! --------------------------------------------------------------
595 recursive subroutine mesh_end(this)
596 class(mesh_t), intent(inout) :: this
597
598 push_sub(mesh_end)
599
600#ifdef HAVE_MPI
601 call lmpi_destroy_shared_memory_window(this%idx%window_grid_to_spatial)
602 call lmpi_destroy_shared_memory_window(this%idx%window_spatial_to_grid)
603 nullify(this%idx%grid_to_spatial_global)
604 nullify(this%idx%spatial_to_grid_global)
605#else
606 safe_deallocate_p(this%idx%grid_to_spatial_global)
607 safe_deallocate_p(this%idx%spatial_to_grid_global)
608#endif
609
610 safe_deallocate_a(this%x)
611 safe_deallocate_a(this%chi)
612 if (this%use_vol_pp .and. accel_is_enabled()) then
613 call accel_free_buffer(this%vol_pp_buffer)
614 call accel_free_buffer(this%sqrt_vol_pp_buffer)
615 end if
616 safe_deallocate_a(this%vol_pp)
617 safe_deallocate_a(this%jacobian_inverse)
618
619 if (this%parallel_in_domains) then
620 call par_vec_end(this%pv)
621 call partition_end(this%partition)
622 end if
623
624 call index_end(this%idx)
625 safe_deallocate_a(this%spacing)
626
627 pop_sub(mesh_end)
628 end subroutine mesh_end
629
630
636 ! ---------------------------------------------------------
637 integer(int64) function mesh_periodic_point(mesh, space, ip) result(ipg)
638 class(mesh_t), intent(in) :: mesh
639 class(space_t),intent(in) :: space
640 integer, intent(in) :: ip
641
642 integer :: ix(space%dim), nr(2, space%dim), idim
643 real(real64) :: xx(space%dim), rr, ufn_re, ufn_im
644
645 ! no push_sub, called too frequently
646
647 call mesh_local_index_to_coords(mesh, ip, ix)
648 nr(1, :) = mesh%idx%nr(1, :) + mesh%idx%enlarge(:)
649 nr(2, :) = mesh%idx%nr(2, :) - mesh%idx%enlarge(:)
650
651 do idim = 1, space%periodic_dim
652 do while (ix(idim) < nr(1, idim))
653 ix(idim) = ix(idim) + mesh%idx%ll(idim)
654 end do
655 do while (ix(idim) > nr(2, idim))
656 ix(idim) = ix(idim) - mesh%idx%ll(idim)
657 end do
658 end do
659
660 ipg = mesh_global_index_from_coords(mesh, ix)
661 assert(ipg > 0)
662
663 if (mesh%masked_periodic_boundaries) then
664 call mesh_r(mesh, ip, rr, coords = xx)
665 call parse_expression(ufn_re, ufn_im, space%dim, xx, rr, m_zero, mesh%periodic_boundary_mask)
666 if (int(ufn_re) == 0) ipg = mesh_local2global(mesh, ip) ! Nothing will be done
667 end if
668
669 end function mesh_periodic_point
670
671 integer(int64) function mesh_periodic_point_global(mesh, space, ipg_in) result(ipg)
672 class(mesh_t), intent(in) :: mesh
673 class(space_t),intent(in) :: space
674 integer(int64),intent(in) :: ipg_in
675
676 integer :: ix(space%dim), nr(2, space%dim), idim
677 real(real64) :: xx(space%dim), rr, ufn_re, ufn_im
678
679 ! no push_sub, called too frequently
680
681 call mesh_global_index_to_coords(mesh, ipg_in, ix)
682 nr(1, :) = mesh%idx%nr(1, :) + mesh%idx%enlarge(:)
683 nr(2, :) = mesh%idx%nr(2, :) - mesh%idx%enlarge(:)
684
685 do idim = 1, space%periodic_dim
686 if (ix(idim) < nr(1, idim)) ix(idim) = ix(idim) + mesh%idx%ll(idim)
687 if (ix(idim) > nr(2, idim)) ix(idim) = ix(idim) - mesh%idx%ll(idim)
688 end do
689
691 assert(ipg > 0)
692
693 if (mesh%masked_periodic_boundaries) then
694 call mesh_r_global(mesh, ipg_in, rr, coords = xx)
695 call parse_expression(ufn_re, ufn_im, space%dim, xx, rr, m_zero, mesh%periodic_boundary_mask)
696 if (int(ufn_re) == 0) ipg = ipg_in ! Nothing will be done
697 end if
698
699 end function mesh_periodic_point_global
700
701
702
703 ! ---------------------------------------------------------
704 real(real64) pure function mesh_global_memory(mesh) result(memory)
705 use iso_c_binding, only: c_sizeof, c_long_long
706 class(mesh_t), intent(in) :: mesh
707
708 ! 2 global index arrays
709 memory = c_sizeof(c_long_long) * real(mesh%np_part_global, real64) * 2
710
711 end function mesh_global_memory
712
713
714 ! ---------------------------------------------------------
715 real(real64) pure function mesh_local_memory(mesh) result(memory)
716 use iso_c_binding, only: c_sizeof, c_long_long
717 class(mesh_t), intent(in) :: mesh
718
719 memory = m_zero
720
721 ! x
722 memory = memory + real64 * real(mesh%np_part, real64) * mesh%idx%dim
723 ! local index arrays
724 memory = memory + c_sizeof(c_long_long) * real(mesh%np_part, real64) * 2
725 end function mesh_local_memory
726
727
730 function mesh_x_global(mesh, ipg) result(xx)
731 class(mesh_t), intent(in) :: mesh
732 integer(int64), intent(in) :: ipg
733 real(real64) :: xx(1:mesh%box%dim)
734
735 real(real64) :: chi(1:mesh%box%dim)
736 integer :: ix(1:mesh%box%dim)
737
738 ! no push_sub because function is called too frequently
739
740 call mesh_global_index_to_coords(mesh, ipg, ix)
741 chi = ix * mesh%spacing
742 xx = mesh%coord_system%to_cartesian(chi)
743
744 end function mesh_x_global
745
746
747 ! ---------------------------------------------------------
748 subroutine mesh_check_symmetries(mesh, symm, periodic_dim)
749 class(mesh_t), intent(in) :: mesh
750 type(symmetries_t), intent(in) :: symm
751 integer, intent(in) :: periodic_dim
752
753 integer :: iop, ip, idim, nops, ix(1:3)
754 real(real64) :: destpoint(1:3), srcpoint(1:3), lsize(1:3), offset(1:3)
755 real(real64), parameter :: tol_spacing = 1e-12_real64
756
757 !If all the axis have the same spacing and the same length
758 !the grid is by obviously symmetric
759 !Indeed, reduced coordinates are proportional to the point index
760 !and the reduced rotation are integer matrices
761 !The result of the product is also proportional to an integer
762 !and therefore belong to the grid.
763 if (mesh%idx%ll(1) == mesh%idx%ll(2) .and. &
764 mesh%idx%ll(2) == mesh%idx%ll(3) .and. &
765 abs(mesh%spacing(1) - mesh%spacing(2)) < tol_spacing .and. &
766 abs(mesh%spacing(2) - mesh%spacing(3)) < tol_spacing) return
767
768 push_sub(mesh_check_symmetries)
769
770 message(1) = "Checking if the real-space grid is symmetric"
771 call messages_info(1)
772
773 lsize(1:3) = real(mesh%idx%ll(1:3), real64)
774 offset(1:3) = real(mesh%idx%nr(1, 1:3) + mesh%idx%enlarge(1:3), real64)
775
776 nops = symmetries_number(symm)
777
778 do ip = 1, mesh%np
779 !We use floating point coordinates to check if the symmetric point
780 !belong to the grid.
781 !If yes, it should have integer reduced coordinates
782 call mesh_local_index_to_coords(mesh, ip, ix)
783 destpoint(1:3) = real(ix(1:3), real64) - offset(1:3)
784 ! offset moves corner of cell to origin, in integer mesh coordinates
785 assert(all(destpoint >= 0))
786 assert(all(destpoint < lsize))
787
788 ! move to center of cell in real coordinates
789 destpoint = destpoint - real(int(lsize)/2, real64)
790
791 !convert to proper reduced coordinates
792 do idim = 1, 3
793 destpoint(idim) = destpoint(idim)/lsize(idim)
794 end do
795
796 ! iterate over all points that go to this point by a symmetry operation
797 do iop = 1, nops
798 srcpoint = symm_op_apply_red(symm%ops(iop), destpoint)
800 !We now come back to what should be an integer, if the symmetric point beloings to the grid
801 do idim = 1, 3
802 srcpoint(idim) = srcpoint(idim)*lsize(idim)
803 end do
804
805 ! move back to reference to origin at corner of cell
806 srcpoint = srcpoint + real(int(lsize)/2, real64)
807
808 ! apply periodic boundary conditions in periodic directions
809 do idim = 1, periodic_dim
810 if (nint(srcpoint(idim)) < 0 .or. nint(srcpoint(idim)) >= lsize(idim)) then
811 srcpoint(idim) = modulo(srcpoint(idim)+m_half*symprec, lsize(idim))
812 end if
813 end do
814 assert(all(srcpoint >= -symprec))
815 assert(all(srcpoint < lsize))
816
817 srcpoint(1:3) = srcpoint(1:3) + offset(1:3)
818
819 if (any(srcpoint-anint(srcpoint)> symprec*m_two)) then
820 message(1) = "The real-space grid breaks at least one of the symmetries of the system."
821 message(2) = "Change your spacing or use SymmetrizeDensity=no."
822 call messages_fatal(2)
823 end if
824 end do
825 end do
826
827 pop_sub(mesh_check_symmetries)
828 end subroutine
829
832 integer(int64) function mesh_global_index_from_coords(mesh, ix) result(index)
833 class(mesh_t), intent(in) :: mesh
834 integer, intent(in) :: ix(:)
835
836 index = index_from_coords(mesh%idx, ix)
838
841 subroutine mesh_global_index_to_coords(mesh, ipg, ix)
842 type(mesh_t), intent(in) :: mesh
843 integer(int64), intent(in) :: ipg
844 integer, contiguous, intent(out) :: ix(:)
845
846 call index_to_coords(mesh%idx, ipg, ix)
847 end subroutine mesh_global_index_to_coords
848
851 integer function mesh_local_index_from_coords(mesh, ix) result(ip)
852 type(mesh_t), intent(in) :: mesh
853 integer, intent(in) :: ix(:)
854
855 integer(int64) :: ipg
856
857 ipg = index_from_coords(mesh%idx, ix)
858 ip = mesh_global2local(mesh, ipg)
860
863 subroutine mesh_local_index_to_coords(mesh, ip, ix)
864 type(mesh_t), intent(in) :: mesh
865 integer, intent(in) :: ip
866 integer, contiguous, intent(out) :: ix(:)
867
868 integer(int64) :: ipg
869
870 ipg = mesh_local2global(mesh, ip)
871 call index_to_coords(mesh%idx, ipg, ix)
872 end subroutine mesh_local_index_to_coords
873
875 integer(int64) function mesh_local2global(mesh, ip) result(ipg)
876 type(mesh_t), intent(in) :: mesh
877 integer, intent(in) :: ip
878
879 ipg = par_vec_local2global(mesh%pv, ip)
880 end function mesh_local2global
881
885 integer function mesh_global2local(mesh, ipg) result(ip)
886 type(mesh_t), intent(in) :: mesh
887 integer(int64), intent(in) :: ipg
888
889 ip = par_vec_global2local(mesh%pv, ipg)
890 end function mesh_global2local
891
892 !-----------------------------------------------------------------------------
894 subroutine mesh_minmaxloc(mesh, min_or_max, rank_min_or_max, op)
895 type(mesh_t), intent(in) :: mesh
896 real(real64), intent(inout) :: min_or_max
897 integer, intent(out) :: rank_min_or_max
898 type(mpi_op), intent(in) :: op
899
900 real(real64) :: loc_in(2), loc_out(2)
901
902 push_sub(mesh_minmaxloc)
903
904 assert(op == mpi_minloc .or. op == mpi_maxloc)
905
906 rank_min_or_max = 0
907 if (mesh%parallel_in_domains) then
908 loc_in(1) = min_or_max
909 loc_in(2) = mesh%mpi_grp%rank
910 call mesh%mpi_grp%allreduce(loc_in, loc_out, 1, mpi_2double_precision, op)
911 min_or_max = loc_out(1)
912 rank_min_or_max = nint(loc_out(2))
913 end if
914
915 pop_sub(mesh_minmaxloc)
916 end subroutine mesh_minmaxloc
917
919 function mesh_red_min(mesh, space)
920 class(mesh_t), intent(in) :: mesh
921 type(space_t), intent(in) :: space
922 real(real64) :: mesh_red_min(space%dim)
923
924 integer :: idir
925
926 push_sub(mesh_red_min)
928 mesh_red_min = m_zero
929 do idir = 1, space%periodic_dim
930 mesh_red_min(idir) = real(mesh%idx%nr(1, idir) + mesh%idx%enlarge(idir), real64) &
931 / real(mesh%idx%ll(idir), real64)
932 end do
933
934 pop_sub(mesh_red_min)
935 end function mesh_red_min
937
938
939#include "undef.F90"
940#include "real.F90"
941#include "mesh_inc.F90"
942
943#include "undef.F90"
944#include "complex.F90"
945#include "mesh_inc.F90"
947#include "undef.F90"
948#include "integer.F90"
949#include "mesh_inc.F90"
950
951#include "undef.F90"
952#include "integer8.F90"
953#include "mesh_inc.F90"
954
955end module mesh_oct_m
956
957
958!! Local Variables:
959!! mode: f90
960!! coding: utf-8
961!! End:
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
This module implements a simple hash table for non-negative integer keys and integer values.
Definition: iihash.F90:127
This module implements the index, used for the mesh points.
Definition: index.F90:124
Definition: io.F90:116
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
integer(int64) function, public mesh_periodic_point(mesh, space, ip)
This function returns the point inside the grid corresponding to a boundary point when PBCs are used....
Definition: mesh.F90:733
subroutine, public mesh_global_index_to_coords(mesh, ipg, ix)
Given a global point index, this function returns the set of integer coordinates of the point.
Definition: mesh.F90:937
integer function, public mesh_local_index_from_coords(mesh, ix)
This function returns the local index of the point for a given vector of integer coordinates.
Definition: mesh.F90:947
subroutine, public mesh_double_box(space, mesh, alpha, db)
finds the dimension of a box doubled in the non-periodic dimensions
Definition: mesh.F90:290
integer(int64) function, public mesh_global_index_from_coords(mesh, ix)
This function returns the true global index of the point for a given vector of integer coordinates.
Definition: mesh.F90:928
subroutine, public mesh_check_symmetries(mesh, symm, periodic_dim)
Definition: mesh.F90:844
subroutine, public mesh_write_info(this, iunit, namespace)
Definition: mesh.F90:315
subroutine, public mesh_local_index_to_coords(mesh, ip, ix)
Given a local point index, this function returns the set of integer coordinates of the point.
Definition: mesh.F90:959
subroutine, public mesh_discretize_values_to_mesh(mesh, values)
Assign a set of values to their nearest discrete points on the mesh.
Definition: mesh.F90:421
integer function, public mesh_nearest_point(mesh, pos, dmin, rankmin)
Returns the index of the point which is nearest to a given vector position pos.
Definition: mesh.F90:391
integer(int64) function, public mesh_periodic_point_global(mesh, space, ipg_in)
Definition: mesh.F90:767
real(real64) pure function, public mesh_global_memory(mesh)
Definition: mesh.F90:800
subroutine, public mesh_read_fingerprint(mesh, dir, filename, mpi_grp, namespace, read_np_part, read_np, bits, type, offset, nn, ierr)
This function reads the fingerprint of a mesh written in filename. If the meshes are equal (same fing...
Definition: mesh.F90:514
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:347
subroutine, public mesh_check_dump_compatibility(mesh, dir, filename, namespace, mpi_grp, grid_changed, grid_reordered, map, ierr)
Definition: mesh.F90:601
real(real64) function, public mesh_gcutoff(mesh)
mesh_gcutoff returns the "natural" band limitation of the grid mesh, in terms of the maximum G vector...
Definition: mesh.F90:455
real(real64) function, dimension(space%dim) mesh_red_min(mesh, space)
Helper routine to compute the minimal index of the mesh in reduced coordinate.
Definition: mesh.F90:1015
subroutine, public mesh_minmaxloc(mesh, min_or_max, rank_min_or_max, op)
Given a local min/max this returns the global min/max and the rank where this is located.
Definition: mesh.F90:990
integer function, public mesh_global2local(mesh, ipg)
This function returns the local mesh index for a given global index.
Definition: mesh.F90:981
recursive subroutine, public mesh_end(this)
Definition: mesh.F90:691
real(real64) pure function, public mesh_local_memory(mesh)
Definition: mesh.F90:811
integer(int64) function, public mesh_local2global(mesh, ip)
This function returns the global mesh index for a given local index.
Definition: mesh.F90:971
real(real64) function, dimension(1:mesh%box%dim), public mesh_x_global(mesh, ipg)
Given a global point index, this function returns the coordinates of the point.
Definition: mesh.F90:826
subroutine mesh_r_global(mesh, ipg, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:367
subroutine, public mesh_write_fingerprint(mesh, dir, filename, mpi_grp, namespace, ierr)
Definition: mesh.F90:465
subroutine mesh_init(this)
Definition: mesh.F90:278
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
This module contains some common usage patterns of MPI routines.
Definition: mpi_lib.F90:117
Some general things and nomenclature:
Definition: par_vec.F90:173
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:225
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
abstract class for basis sets
This data type defines a line, and a regular grid defined on this line (or rather,...
Definition: mesh.F90:266
define a grid on a plane.
Definition: mesh.F90:254
Describes mesh distribution to nodes.
Definition: mesh.F90:188
int true(void)