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
27 use box_oct_m
28 use comm_oct_m
30 use debug_oct_m
31 use global_oct_m
32 use iihash_oct_m
33 use index_oct_m
34 use io_oct_m
37 use mpi_oct_m
42 use parser_oct_m
44 use space_oct_m
47 use unit_oct_m
49
50 implicit none
51
52 private
53 public :: &
54 mesh_t, &
58 mesh_end, &
60 mesh_r, &
80
92 type, extends(basis_set_abst_t) :: mesh_t
93 ! Components are public by default
94 class(box_t), pointer :: box
95 class(coordinate_system_t), pointer :: coord_system
96 type(index_t) :: idx
97 logical :: use_curvilinear
98
99 real(real64), allocatable :: spacing(:)
100
101 ! When running serially, the local number of points is
102 ! equal to the global number of points.
103 ! Otherwise, the next two are different on each node.
104 integer :: np
105 integer :: np_part
106 integer(int64) :: np_global
107 integer(int64) :: np_part_global
108 logical :: parallel_in_domains
109 type(mpi_grp_t) :: mpi_grp
110 type(par_vec_t) :: pv
111 type(partition_t) :: partition
112
113 real(real64), allocatable :: x(:,:)
114 real(real64), allocatable :: x_t(:,:)
115 real(real64), allocatable :: chi(:,:)
116 real(real64) :: volume_element
117 real(real64), allocatable :: vol_pp(:)
118 real(real64), allocatable :: jacobian_inverse(:,:,:)
119
120 logical :: masked_periodic_boundaries
121 character(len=256) :: periodic_boundary_mask
123 contains
124 procedure :: end => mesh_end
125 procedure :: init => mesh_init
126 procedure :: write_info => mesh_write_info
127 procedure :: dmesh_allreduce_0, zmesh_allreduce_0, imesh_allreduce_0, lmesh_allreduce_0
128 procedure :: dmesh_allreduce_1, zmesh_allreduce_1, imesh_allreduce_1, lmesh_allreduce_1
129 procedure :: dmesh_allreduce_2, zmesh_allreduce_2, imesh_allreduce_2, lmesh_allreduce_2
130 procedure :: dmesh_allreduce_3, zmesh_allreduce_3, imesh_allreduce_3, lmesh_allreduce_3
131 procedure :: dmesh_allreduce_4, zmesh_allreduce_4, imesh_allreduce_4, lmesh_allreduce_4
132 procedure :: dmesh_allreduce_5, zmesh_allreduce_5, imesh_allreduce_5, lmesh_allreduce_5
133 procedure :: dmesh_allreduce_6, zmesh_allreduce_6, imesh_allreduce_6, lmesh_allreduce_6
134 generic :: allreduce => dmesh_allreduce_0, zmesh_allreduce_0, imesh_allreduce_0, lmesh_allreduce_0
135 generic :: allreduce => dmesh_allreduce_1, zmesh_allreduce_1, imesh_allreduce_1, lmesh_allreduce_1
136 generic :: allreduce => dmesh_allreduce_2, zmesh_allreduce_2, imesh_allreduce_2, lmesh_allreduce_2
137 generic :: allreduce => dmesh_allreduce_3, zmesh_allreduce_3, imesh_allreduce_3, lmesh_allreduce_3
138 generic :: allreduce => dmesh_allreduce_4, zmesh_allreduce_4, imesh_allreduce_4, lmesh_allreduce_4
139 generic :: allreduce => dmesh_allreduce_5, zmesh_allreduce_5, imesh_allreduce_5, lmesh_allreduce_5
140 generic :: allreduce => dmesh_allreduce_6, zmesh_allreduce_6, imesh_allreduce_6, lmesh_allreduce_6
141 procedure :: red_min => mesh_red_min
142 end type mesh_t
143
155 type mesh_plane_t
156 ! Components are public by default
157 real(real64) :: n(3)
158 real(real64) :: u(3), v(3)
159 real(real64) :: origin(3)
160 real(real64) :: spacing
161 integer :: nu, mu, nv, mv
162 end type mesh_plane_t
163
167 type mesh_line_t
168 ! Components are public by default
169 real(real64) :: n(2)
170 real(real64) :: u(2)
171 real(real64) :: origin(2)
172 real(real64) :: spacing
173 integer :: nu, mu
174 end type mesh_line_t
175
176contains
177
178 subroutine mesh_init(this)
179 class(mesh_t), intent(inout) :: this
180
181 push_sub(mesh_init)
182
183 call this%set_time_dependent(.false.)
184
185 pop_sub(mesh_init)
186 end subroutine mesh_init
188! ---------------------------------------------------------
190 subroutine mesh_double_box(space, mesh, alpha, db)
191 class(space_t), intent(in) :: space
192 type(mesh_t), intent(in) :: mesh
193 real(real64), intent(in) :: alpha
194 integer, intent(out) :: db(:)
195
196 integer :: idir
197
198 push_sub(mesh_double_box)
200 db = 1
202 ! double mesh with 2n points
203 do idir = 1, space%periodic_dim
204 db(idir) = mesh%idx%ll(idir)
205 end do
206 do idir = space%periodic_dim + 1, space%dim
207 db(idir) = nint(alpha * (mesh%idx%ll(idir) - 1)) + 1
208 end do
211 end subroutine mesh_double_box
214 ! ---------------------------------------------------------
215 subroutine mesh_write_info(this, iunit, namespace)
216 class(mesh_t), intent(in) :: this
217 integer, optional, intent(in) :: iunit
218 type(namespace_t), optional, intent(in) :: namespace
220 integer :: ii
221 real(real64) :: cutoff
225 write(message(1),'(3a)') ' Spacing [', trim(units_abbrev(units_out%length)), '] = ('
226 do ii = 1, this%box%dim
227 if (ii > 1) write(message(1), '(2a)') trim(message(1)), ','
228 write(message(1), '(a,f6.3)') trim(message(1)), units_from_atomic(units_out%length, this%spacing(ii))
229 end do
230 write(message(1), '(5a,f12.5)') trim(message(1)), ') ', &
231 ' volume/point [', trim(units_abbrev(units_out%length**this%box%dim)), '] = ', &
232 units_from_atomic(units_out%length**this%box%dim, this%vol_pp(1))
234 write(message(2),'(a, i10)') ' # inner mesh = ', this%np_global
235 write(message(3),'(a, i10)') ' # total mesh = ', this%np_part_global
237 cutoff = mesh_gcutoff(this)**2 / m_two
238 write(message(4),'(3a,f12.6,a,f12.6)') ' Grid Cutoff [', trim(units_abbrev(units_out%energy)),'] = ', &
239 units_from_atomic(units_out%energy, cutoff), ' Grid Cutoff [Ry] = ', cutoff * m_two
240 call messages_info(4, iunit=iunit, namespace=namespace)
241
242 pop_sub(mesh_write_info)
243 end subroutine mesh_write_info
244
245
247 pure subroutine mesh_r(mesh, ip, rr, origin, coords)
248 class(mesh_t), intent(in) :: mesh
249 integer, intent(in) :: ip
250 real(real64), intent(out) :: rr
251 real(real64), intent(in), optional :: origin(:)
252 real(real64), intent(out), optional :: coords(:)
254 real(real64) :: xx(1:mesh%box%dim)
256 xx = mesh%x(:, ip)
257 if (present(origin)) xx = xx - origin
258 rr = norm2(xx)
259
260 if (present(coords)) then
261 coords = xx
262 end if
263
264 end subroutine mesh_r
267 subroutine mesh_r_global(mesh, ipg, rr, origin, coords)
268 class(mesh_t), intent(in) :: mesh
269 integer(int64),intent(in) :: ipg
270 real(real64), intent(out) :: rr
271 real(real64), intent(in), optional :: origin(:)
272 real(real64), intent(out), optional :: coords(:)
274 real(real64) :: xx(1:mesh%box%dim)
275
276 xx = mesh_x_global(mesh, ipg)
277 if (present(origin)) xx = xx - origin
278 rr = norm2(xx)
279
280 if (present(coords)) then
281 coords = xx
282 end if
283
284 end subroutine mesh_r_global
286
291 integer function mesh_nearest_point(mesh, pos, dmin, rankmin) result(ind)
292 class(mesh_t),intent(in) :: mesh
293 real(real64), intent(in) :: pos(:)
294 real(real64), intent(out) :: dmin
295 integer, intent(out) :: rankmin
296 ! This returns 0 in the absence of domain decomposition
297
298 real(real64) :: dd
299 integer :: imin, ip
300
301 push_sub(mesh_nearest_point)
302
303 ! find the point of the grid that is closer to the atom
304 dmin = m_zero
305 do ip = 1, mesh%np
306 dd = sum((pos - mesh%x(:, ip))**2)
307 if ((dd < dmin) .or. (ip == 1)) then
308 imin = ip
309 dmin = dd
310 end if
311 end do
312
313 call mesh_minmaxloc(mesh, dmin, rankmin, mpi_minloc)
314 call mesh%mpi_grp%bcast(imin, 1, mpi_integer, rankmin)
315
316 ind = imin
317 pop_sub(mesh_nearest_point)
318 end function mesh_nearest_point
319
321 subroutine mesh_discretize_values_to_mesh(mesh, values)
322 class(mesh_t), intent(in ) :: mesh
323 real(real64), intent(inout) :: values(:, :)
324 ! Out: Values discretized to mesh points
325 integer :: i, ip, ndim
326 integer :: process
327 real(real64) :: dummy
328
330
331 if (mesh%parallel_in_domains) then
332 ndim = size(values, 1)
333 do i = 1, size(values, 2)
334 ip = mesh_nearest_point(mesh, values(:, i), dummy, process)
335 ! ip is defined for `process`, only
336 if (mesh%mpi_grp%rank == process) values(:, i) = mesh%x(:, ip)
337 call mesh%mpi_grp%bcast(values(:, i), ndim, mpi_double_precision, process)
338 enddo
339 else
340 do i = 1, size(values, 2)
341 ip = mesh_nearest_point(mesh, values(:, i), dummy, process)
342 values(:, i) = mesh%x(:, ip)
343 enddo
344 endif
345
347
348 end subroutine mesh_discretize_values_to_mesh
349
350 ! --------------------------------------------------------------
354 ! --------------------------------------------------------------
355 real(real64) function mesh_gcutoff(mesh) result(gmax)
356 class(mesh_t), intent(in) :: mesh
357
358 push_sub(mesh_gcutoff)
359 gmax = m_pi / (maxval(mesh%spacing))
360
361 pop_sub(mesh_gcutoff)
362 end function mesh_gcutoff
363
364 ! --------------------------------------------------------------
365 subroutine mesh_write_fingerprint(mesh, dir, filename, mpi_grp, namespace, ierr)
366 type(mesh_t), intent(in) :: mesh
367 character(len=*), intent(in) :: dir
368 character(len=*), intent(in) :: filename
369 type(mpi_grp_t), intent(in) :: mpi_grp
370 type(namespace_t),intent(in) :: namespace
371 integer, intent(out) :: ierr
372
373 integer :: iunit, ii
374
375 push_sub(mesh_write_fingerprint)
376
377 ierr = 0
378
379 iunit = io_open(trim(dir)//"/"//trim(filename), namespace, action='write', &
380 die=.false., grp=mpi_grp)
381 if (iunit == -1) then
382 message(1) = "Unable to open file '"//trim(dir)//"/"//trim(filename)//"'."
383 call messages_warning(1, namespace=namespace)
384 ierr = ierr + 1
385 else
386 if (mpi_grp%is_root()) then
387 write(iunit, '(a20,i21)') 'np_part_global= ', mesh%np_part_global
388 write(iunit, '(a20,i21)') 'np_global= ', mesh%np_global
389 write(iunit, '(a20,i21)') 'algorithm= ', 1
390 write(iunit, '(a20,i21)') 'checksum= ', mesh%idx%checksum
391 write(iunit, '(a20,i21)') 'bits= ', mesh%idx%bits
392 write(iunit, '(a20,i21)') 'dim= ', mesh%idx%dim
393 write(iunit, '(a20,i21)') 'type= ', mesh%idx%type
394 do ii = 1, mesh%idx%dim
395 write(iunit, '(a7,i2,a11,i21)') 'offset(',ii,')= ', mesh%idx%offset(ii)
396 end do
397 do ii = 1, mesh%idx%dim
398 write(iunit, '(a7,i2,a11,i21)') 'nn(',ii,')= ', mesh%idx%nr(2, ii) - mesh%idx%nr(1, ii) + 1
399 end do
400 end if
401 call io_close(iunit, grp=mpi_grp)
402 end if
403
405 end subroutine mesh_write_fingerprint
406
407
408 ! -----------------------------------------------------------------------
413 subroutine mesh_read_fingerprint(mesh, dir, filename, mpi_grp, namespace, &
414 read_np_part, read_np, bits, type, offset, nn, ierr)
415 type(mesh_t), intent(in) :: mesh
416 character(len=*), intent(in) :: dir
417 character(len=*), intent(in) :: filename
418 type(mpi_grp_t), intent(in) :: mpi_grp
419 type(namespace_t),intent(in) :: namespace
420 integer(int64), intent(out) :: read_np_part
421 integer(int64), intent(out) :: read_np
422 integer, intent(out) :: bits
423 integer, intent(out) :: type
424 integer, intent(out) :: offset(1:mesh%idx%dim)
425 integer, intent(out) :: nn(1:mesh%idx%dim)
426 integer, intent(out) :: ierr
427
428 character(len=20) :: str
429 character(len=100) :: lines(7)
430 integer :: iunit, algorithm, dim, err, ii
431 integer(int64) :: checksum
432
433 push_sub(mesh_read_fingerprint)
434
435 ierr = 0
436
437 read_np_part = 0_int64
438 read_np = 0_int64
439
440 iunit = io_open(trim(dir)//"/"//trim(filename), namespace, action='read', &
441 status='old', die=.false., grp=mpi_grp)
442 if (iunit == -1) then
443 ierr = ierr + 1
444 message(1) = "Unable to open file '"//trim(dir)//"/"//trim(filename)//"'."
445 call messages_warning(1, namespace=namespace)
446 else
447 call iopar_read(mpi_grp, iunit, lines, 7, err)
448 if (err /= 0) then
449 ierr = ierr + 4
450 else
451 read(lines(1), '(a20,i21)') str, read_np_part
452 read(lines(2), '(a20,i21)') str, read_np
453 read(lines(3), '(a20,i21)') str, algorithm
454 read(lines(4), '(a20,i21)') str, checksum
455 read(lines(5), '(a20,i21)') str, bits
456 read(lines(6), '(a20,i21)') str, dim
457 read(lines(7), '(a20,i21)') str, type
458 ! only allow restarting simulations with the same dimensions
459 if (dim /= mesh%idx%dim) then
460 ierr = ierr + 8
461 else
462 ! read offset, has dim lines
463 call iopar_read(mpi_grp, iunit, lines, dim, err)
464 if (err /= 0) then
465 ierr = ierr + 4
466 else
467 do ii = 1, dim
468 read(lines(ii), '(a20,i21)') str, offset(ii)
469 end do
470 end if
471
472 ! read nn, has dim lines
473 call iopar_read(mpi_grp, iunit, lines, dim, err)
474 if (err /= 0) then
475 ierr = ierr + 4
476 else
477 do ii = 1, dim
478 read(lines(ii), '(a20,i21)') str, nn(ii)
479 end do
480 end if
481 end if
482
483 assert(read_np_part >= read_np)
484
485 if (read_np_part == mesh%np_part_global &
486 .and. read_np == mesh%np_global &
487 .and. algorithm == 1 &
488 .and. checksum == mesh%idx%checksum) then
489 read_np_part = 0
490 read_np = 0
491 end if
492 end if
493
494 call io_close(iunit, grp=mpi_grp)
495 end if
496
497 pop_sub(mesh_read_fingerprint)
498 end subroutine mesh_read_fingerprint
499
500 ! ---------------------------------------------------------
501 subroutine mesh_check_dump_compatibility(mesh, dir, filename, namespace, mpi_grp, grid_changed, grid_reordered, map, ierr)
502 type(mesh_t), intent(in) :: mesh
503 character(len=*), intent(in) :: dir
504 character(len=*), intent(in) :: filename
505 type(namespace_t), intent(in) :: namespace
506 type(mpi_grp_t), intent(in) :: mpi_grp
507 logical, intent(out) :: grid_changed
508 logical, intent(out) :: grid_reordered
509 integer(int64), allocatable, intent(out) :: map(:)
510 integer, intent(out) :: ierr
511
512 integer(int64) :: ipg, ipg_new, read_np_part, read_np
513 integer :: err, idir
514 integer :: bits, type, offset(mesh%idx%dim), point(mesh%idx%dim), nn(mesh%idx%dim)
515 integer(int64), allocatable :: read_indices(:)
516 type(index_t) :: idx_old
517
519
520 ierr = 0
521
522 grid_changed = .false.
523 grid_reordered = .false.
524
525 ! Read the mesh fingerprint
526 call mesh_read_fingerprint(mesh, dir, filename, mpi_grp, namespace, read_np_part, read_np, &
527 bits, type, offset, nn, err)
528 if (err /= 0) then
529 ierr = 1
530 message(1) = "Unable to read mesh fingerprint from '"//trim(dir)//"/"//trim(filename)//"'."
531 call messages_warning(1, namespace=namespace)
532
533 else if (read_np > 0) then
534 if (.not. associated(mesh%box)) then
535 ! We can only check the compatibility of two meshes that have different fingerprints if we also
536 ! have the simulation box. In the case we do not, we will assume that the fingerprint is enough.
537 ierr = ierr + 2
538 else
539 grid_changed = .true.
540
541 ! perhaps only the order of the points changed, this can only
542 ! happen if the number of points is the same and no points maps
543 ! to zero (this is checked below)
544 grid_reordered = (read_np == mesh%np_global)
545
546 ! the grid is different, so we read the coordinates.
547 safe_allocate(read_indices(1:read_np_part))
548 call io_binary_read(trim(io_workpath(dir, namespace))//"/indices.obf", read_np_part, &
549 read_indices, err)
550 if (err /= 0) then
551 ierr = ierr + 4
552 message(1) = "Unable to read index map from '"//trim(dir)//"'."
553 call messages_warning(1, namespace=namespace)
554 else
555 ! dummy index object
556 call index_init(idx_old, mesh%idx%dim)
557 idx_old%type = type
558 idx_old%bits = bits
559 idx_old%nr(1, :) = -offset
560 idx_old%nr(2, :) = -offset + nn - 1
561 idx_old%offset = offset
562 idx_old%stride(1) = 1
563 do idir = 2, mesh%idx%dim
564 idx_old%stride(idir) = idx_old%stride(idir-1) * nn(idir-1)
565 end do
566 ! generate the map
567 safe_allocate(map(1:read_np))
568 do ipg = 1, read_np
569 ! get nd-index from old 1d index
570 call index_spatial_to_point(idx_old, mesh%idx%dim, read_indices(ipg), point)
571 ! get new global index
572 ipg_new = mesh_global_index_from_coords(mesh, point)
573 map(ipg) = ipg_new
574 ! ignore boundary points
575 if (map(ipg) > mesh%np_global) map(ipg) = 0
576 ! if the map is zero for one point, it is not a simple reordering
577 if (map(ipg) == 0) grid_reordered = .false.
578 end do
579 call index_end(idx_old)
580 end if
581
582 safe_deallocate_a(read_indices)
583 end if
584 end if
585
587 end subroutine mesh_check_dump_compatibility
588
589
590 ! --------------------------------------------------------------
591 recursive subroutine mesh_end(this)
592 class(mesh_t), intent(inout) :: this
593
594 push_sub(mesh_end)
595
596#ifdef HAVE_MPI
597 call lmpi_destroy_shared_memory_window(this%idx%window_grid_to_spatial)
598 call lmpi_destroy_shared_memory_window(this%idx%window_spatial_to_grid)
599 nullify(this%idx%grid_to_spatial_global)
600 nullify(this%idx%spatial_to_grid_global)
601#else
602 safe_deallocate_p(this%idx%grid_to_spatial_global)
603 safe_deallocate_p(this%idx%spatial_to_grid_global)
604#endif
605
606 safe_deallocate_a(this%x)
607 safe_deallocate_a(this%chi)
608 safe_deallocate_a(this%vol_pp)
609 safe_deallocate_a(this%jacobian_inverse)
610
611 if (this%parallel_in_domains) then
612 call par_vec_end(this%pv)
613 call partition_end(this%partition)
614 end if
615
616 call index_end(this%idx)
617 safe_deallocate_a(this%spacing)
618
619 pop_sub(mesh_end)
620 end subroutine mesh_end
621
622
628 ! ---------------------------------------------------------
629 integer(int64) function mesh_periodic_point(mesh, space, ip) result(ipg)
630 class(mesh_t), intent(in) :: mesh
631 class(space_t),intent(in) :: space
632 integer, intent(in) :: ip
633
634 integer :: ix(space%dim), nr(2, space%dim), idim
635 real(real64) :: xx(space%dim), rr, ufn_re, ufn_im
636
637 ! no push_sub, called too frequently
638
639 call mesh_local_index_to_coords(mesh, ip, ix)
640 nr(1, :) = mesh%idx%nr(1, :) + mesh%idx%enlarge(:)
641 nr(2, :) = mesh%idx%nr(2, :) - mesh%idx%enlarge(:)
642
643 do idim = 1, space%periodic_dim
644 do while (ix(idim) < nr(1, idim))
645 ix(idim) = ix(idim) + mesh%idx%ll(idim)
646 end do
647 do while (ix(idim) > nr(2, idim))
648 ix(idim) = ix(idim) - mesh%idx%ll(idim)
649 end do
650 end do
651
652 ipg = mesh_global_index_from_coords(mesh, ix)
653 assert(ipg > 0)
654
655 if (mesh%masked_periodic_boundaries) then
656 call mesh_r(mesh, ip, rr, coords = xx)
657 call parse_expression(ufn_re, ufn_im, space%dim, xx, rr, m_zero, mesh%periodic_boundary_mask)
658 if (int(ufn_re) == 0) ipg = mesh_local2global(mesh, ip) ! Nothing will be done
659 end if
660
661 end function mesh_periodic_point
662
663 integer(int64) function mesh_periodic_point_global(mesh, space, ipg_in) result(ipg)
664 class(mesh_t), intent(in) :: mesh
665 class(space_t),intent(in) :: space
666 integer(int64),intent(in) :: ipg_in
667
668 integer :: ix(space%dim), nr(2, space%dim), idim
669 real(real64) :: xx(space%dim), rr, ufn_re, ufn_im
670
671 ! no push_sub, called too frequently
672
673 call mesh_global_index_to_coords(mesh, ipg_in, ix)
674 nr(1, :) = mesh%idx%nr(1, :) + mesh%idx%enlarge(:)
675 nr(2, :) = mesh%idx%nr(2, :) - mesh%idx%enlarge(:)
676
677 do idim = 1, space%periodic_dim
678 if (ix(idim) < nr(1, idim)) ix(idim) = ix(idim) + mesh%idx%ll(idim)
679 if (ix(idim) > nr(2, idim)) ix(idim) = ix(idim) - mesh%idx%ll(idim)
680 end do
681
682 ipg = mesh_global_index_from_coords(mesh, ix)
683 assert(ipg > 0)
684
685 if (mesh%masked_periodic_boundaries) then
686 call mesh_r_global(mesh, ipg_in, rr, coords = xx)
687 call parse_expression(ufn_re, ufn_im, space%dim, xx, rr, m_zero, mesh%periodic_boundary_mask)
688 if (int(ufn_re) == 0) ipg = ipg_in ! Nothing will be done
689 end if
690
691 end function mesh_periodic_point_global
692
693
694
695 ! ---------------------------------------------------------
696 real(real64) pure function mesh_global_memory(mesh) result(memory)
697 use iso_c_binding, only: c_sizeof, c_long_long
698 class(mesh_t), intent(in) :: mesh
699
700 ! 2 global index arrays
701 memory = c_sizeof(c_long_long) * real(mesh%np_part_global, real64) * 2
702
703 end function mesh_global_memory
704
705
706 ! ---------------------------------------------------------
707 real(real64) pure function mesh_local_memory(mesh) result(memory)
708 use iso_c_binding, only: c_sizeof, c_long_long
709 class(mesh_t), intent(in) :: mesh
710
711 memory = m_zero
712
713 ! x
714 memory = memory + real64 * real(mesh%np_part, real64) * mesh%idx%dim
715 ! local index arrays
716 memory = memory + c_sizeof(c_long_long) * real(mesh%np_part, real64) * 2
717 end function mesh_local_memory
718
719
722 function mesh_x_global(mesh, ipg) result(xx)
723 class(mesh_t), intent(in) :: mesh
724 integer(int64), intent(in) :: ipg
725 real(real64) :: xx(1:mesh%box%dim)
726
727 real(real64) :: chi(1:mesh%box%dim)
728 integer :: ix(1:mesh%box%dim)
729
730 ! no push_sub because function is called too frequently
731
732 call mesh_global_index_to_coords(mesh, ipg, ix)
733 chi = ix * mesh%spacing
734 xx = mesh%coord_system%to_cartesian(chi)
735
736 end function mesh_x_global
737
738
739 ! ---------------------------------------------------------
740 subroutine mesh_check_symmetries(mesh, symm, periodic_dim)
741 class(mesh_t), intent(in) :: mesh
742 type(symmetries_t), intent(in) :: symm
743 integer, intent(in) :: periodic_dim
744
745 integer :: iop, ip, idim, nops, ix(1:3)
746 real(real64) :: destpoint(1:3), srcpoint(1:3), lsize(1:3), offset(1:3)
747 real(real64), parameter :: tol_spacing = 1e-12_real64
748
749 !If all the axis have the same spacing and the same length
750 !the grid is by obviously symmetric
751 !Indeed, reduced coordinates are proportional to the point index
752 !and the reduced rotation are integer matrices
753 !The result of the product is also proportional to an integer
754 !and therefore belong to the grid.
755 if (mesh%idx%ll(1) == mesh%idx%ll(2) .and. &
756 mesh%idx%ll(2) == mesh%idx%ll(3) .and. &
757 abs(mesh%spacing(1) - mesh%spacing(2)) < tol_spacing .and. &
758 abs(mesh%spacing(2) - mesh%spacing(3)) < tol_spacing) return
759
760 push_sub(mesh_check_symmetries)
761
762 message(1) = "Checking if the real-space grid is symmetric"
763 call messages_info(1)
764
765 lsize(1:3) = real(mesh%idx%ll(1:3), real64)
766 offset(1:3) = real(mesh%idx%nr(1, 1:3) + mesh%idx%enlarge(1:3), real64)
767
768 nops = symmetries_number(symm)
769
770 do ip = 1, mesh%np
771 !We use floating point coordinates to check if the symmetric point
772 !belong to the grid.
773 !If yes, it should have integer reduced coordinates
774 call mesh_local_index_to_coords(mesh, ip, ix)
775 destpoint(1:3) = real(ix(1:3), real64) - offset(1:3)
776 ! offset moves corner of cell to origin, in integer mesh coordinates
777 assert(all(destpoint >= 0))
778 assert(all(destpoint < lsize))
779
780 ! move to center of cell in real coordinates
781 destpoint = destpoint - real(int(lsize)/2, real64)
782
783 !convert to proper reduced coordinates
784 do idim = 1, 3
785 destpoint(idim) = destpoint(idim)/lsize(idim)
786 end do
787
788 ! iterate over all points that go to this point by a symmetry operation
789 do iop = 1, nops
790 srcpoint = symm_op_apply_red(symm%ops(iop), destpoint)
792 !We now come back to what should be an integer, if the symmetric point beloings to the grid
793 do idim = 1, 3
794 srcpoint(idim) = srcpoint(idim)*lsize(idim)
795 end do
796
797 ! move back to reference to origin at corner of cell
798 srcpoint = srcpoint + real(int(lsize)/2, real64)
799
800 ! apply periodic boundary conditions in periodic directions
801 do idim = 1, periodic_dim
802 if (nint(srcpoint(idim)) < 0 .or. nint(srcpoint(idim)) >= lsize(idim)) then
803 srcpoint(idim) = modulo(srcpoint(idim)+m_half*symprec, lsize(idim))
804 end if
805 end do
806 assert(all(srcpoint >= -symprec))
807 assert(all(srcpoint < lsize))
808
809 srcpoint(1:3) = srcpoint(1:3) + offset(1:3)
810
811 if (any(srcpoint-anint(srcpoint)> symprec*m_two)) then
812 message(1) = "The real-space grid breaks at least one of the symmetries of the system."
813 message(2) = "Change your spacing or use SymmetrizeDensity=no."
814 call messages_fatal(2)
815 end if
816 end do
817 end do
818
819 pop_sub(mesh_check_symmetries)
820 end subroutine
821
824 integer(int64) function mesh_global_index_from_coords(mesh, ix) result(index)
825 class(mesh_t), intent(in) :: mesh
826 integer, intent(in) :: ix(:)
827
828 index = index_from_coords(mesh%idx, ix)
830
833 subroutine mesh_global_index_to_coords(mesh, ipg, ix)
834 type(mesh_t), intent(in) :: mesh
835 integer(int64), intent(in) :: ipg
836 integer, intent(out) :: ix(:)
837
838 call index_to_coords(mesh%idx, ipg, ix)
839 end subroutine mesh_global_index_to_coords
840
843 integer function mesh_local_index_from_coords(mesh, ix) result(ip)
844 type(mesh_t), intent(in) :: mesh
845 integer, intent(in) :: ix(:)
846
847 integer(int64) :: ipg
848
849 ipg = index_from_coords(mesh%idx, ix)
850 ip = mesh_global2local(mesh, ipg)
852
855 subroutine mesh_local_index_to_coords(mesh, ip, ix)
856 type(mesh_t), intent(in) :: mesh
857 integer, intent(in) :: ip
858 integer, intent(out) :: ix(:)
859
860 integer(int64) :: ipg
861
862 ipg = mesh_local2global(mesh, ip)
863 call index_to_coords(mesh%idx, ipg, ix)
864 end subroutine mesh_local_index_to_coords
865
867 integer(int64) function mesh_local2global(mesh, ip) result(ipg)
868 type(mesh_t), intent(in) :: mesh
869 integer, intent(in) :: ip
870
871 ipg = par_vec_local2global(mesh%pv, ip)
872 end function mesh_local2global
873
877 integer function mesh_global2local(mesh, ipg) result(ip)
878 type(mesh_t), intent(in) :: mesh
879 integer(int64), intent(in) :: ipg
880
881 ip = par_vec_global2local(mesh%pv, ipg)
882 end function mesh_global2local
883
884 !-----------------------------------------------------------------------------
886 subroutine mesh_minmaxloc(mesh, min_or_max, rank_min_or_max, op)
887 type(mesh_t), intent(in) :: mesh
888 real(real64), intent(inout) :: min_or_max
889 integer, intent(out) :: rank_min_or_max
890 type(mpi_op), intent(in) :: op
891
892 real(real64) :: loc_in(2), loc_out(2)
893
894 push_sub(mesh_minmaxloc)
895
896 assert(op == mpi_minloc .or. op == mpi_maxloc)
897
898 rank_min_or_max = 0
899 if (mesh%parallel_in_domains) then
900 loc_in(1) = min_or_max
901 loc_in(2) = mesh%mpi_grp%rank
902 call mesh%mpi_grp%allreduce(loc_in, loc_out, 1, mpi_2double_precision, op)
903 min_or_max = loc_out(1)
904 rank_min_or_max = nint(loc_out(2))
905 end if
906
907 pop_sub(mesh_minmaxloc)
908 end subroutine mesh_minmaxloc
909
911 function mesh_red_min(mesh, space)
912 class(mesh_t), intent(in) :: mesh
913 type(space_t), intent(in) :: space
914 real(real64) :: mesh_red_min(space%dim)
915
916 integer :: idir
917
918 push_sub(mesh_red_min)
920 mesh_red_min = m_zero
921 do idir = 1, space%periodic_dim
922 mesh_red_min(idir) = real(mesh%idx%nr(1, idir) + mesh%idx%enlarge(idir), real64) &
923 / real(mesh%idx%ll(idir), real64)
924 end do
925
926 pop_sub(mesh_red_min)
927 end function mesh_red_min
929
930
931#include "undef.F90"
932#include "real.F90"
933#include "mesh_inc.F90"
934
935#include "undef.F90"
936#include "complex.F90"
937#include "mesh_inc.F90"
939#include "undef.F90"
940#include "integer.F90"
941#include "mesh_inc.F90"
942
943#include "undef.F90"
944#include "integer8.F90"
945#include "mesh_inc.F90"
946
947end module mesh_oct_m
948
949
950!! Local Variables:
951!! mode: f90
952!! coding: utf-8
953!! 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:725
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:929
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
subroutine, public mesh_double_box(space, mesh, alpha, db)
finds the dimension of a box doubled in the non-periodic dimensions
Definition: mesh.F90:286
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:920
subroutine, public mesh_check_symmetries(mesh, symm, periodic_dim)
Definition: mesh.F90:836
subroutine, public mesh_write_info(this, iunit, namespace)
Definition: mesh.F90:311
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:951
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:417
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:387
integer(int64) function, public mesh_periodic_point_global(mesh, space, ipg_in)
Definition: mesh.F90:759
real(real64) pure function, public mesh_global_memory(mesh)
Definition: mesh.F90:792
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:510
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:343
subroutine, public mesh_check_dump_compatibility(mesh, dir, filename, namespace, mpi_grp, grid_changed, grid_reordered, map, ierr)
Definition: mesh.F90:597
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:451
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:1007
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:982
integer function, public mesh_global2local(mesh, ipg)
This function returns the local mesh index for a given global index.
Definition: mesh.F90:973
recursive subroutine, public mesh_end(this)
Definition: mesh.F90:687
real(real64) pure function, public mesh_local_memory(mesh)
Definition: mesh.F90:803
integer(int64) function, public mesh_local2global(mesh, ip)
This function returns the global mesh index for a given local index.
Definition: mesh.F90:963
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:818
subroutine mesh_r_global(mesh, ipg, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:363
subroutine, public mesh_write_fingerprint(mesh, dir, filename, mpi_grp, namespace, ierr)
Definition: mesh.F90:461
subroutine mesh_init(this)
Definition: mesh.F90:274
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:262
define a grid on a plane.
Definition: mesh.F90:250
Describes mesh distribution to nodes.
Definition: mesh.F90:187
int true(void)