Octopus
mesh_init.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
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
24module mesh_init_oct_m
25 use accel_oct_m
26 use types_oct_m
28 use box_oct_m
32 use debug_oct_m
33 use global_oct_m
34 use iihash_oct_m
35 use index_oct_m
36 use math_oct_m
38 use mesh_oct_m
42 use mpi_oct_m
47 use parser_oct_m
51 use sort_oct_m
52 use space_oct_m
54 use utils_oct_m
55
56 implicit none
57
58 private
59 public :: &
63
64
65 integer, parameter :: INNER_POINT = 1
66 integer, parameter :: ENLARGEMENT_POINT = 2
67 integer, parameter :: BOUNDARY = -1
68
69contains
70
71! ---------------------------------------------------------
78 subroutine mesh_init_stage_1(mesh, namespace, space, box, coord_system, spacing, enlarge)
79 class(mesh_t), intent(inout) :: mesh
80 type(namespace_t), intent(in) :: namespace
81 class(space_t), intent(in) :: space
82 class(box_t), target, intent(in) :: box
83 class(coordinate_system_t), target, intent(in) :: coord_system
84 real(real64), intent(in) :: spacing(1:space%dim)
85 integer, intent(in) :: enlarge(1:space%dim)
86
87 integer :: idir, jj, delta
88 real(real64) :: x(space%dim), chi(space%dim), spacing_new(-1:1), box_bounds(2, space%dim)
89 logical :: out
90
91 push_sub_with_profile(mesh_init_stage_1)
92
93 mesh%box => box
94
95 safe_allocate(mesh%spacing(1:space%dim))
96 mesh%spacing = spacing ! this number can change in the following
97
98 mesh%use_curvilinear = coord_system%local_basis
99 ! the volume element is per point for curvilinear coordinates
100 mesh%use_vol_pp = mesh%use_curvilinear
101 mesh%coord_system => coord_system
102
103 call index_init(mesh%idx, space%dim)
104 mesh%idx%enlarge = enlarge
105
106 ! get box bounds along the axes that generate the grid points
107 select type (coord_system)
108 class is (affine_coordinates_t)
109 box_bounds = box%bounds(coord_system%basis)
110 class default
111 box_bounds = box%bounds()
112 end select
113
114 ! adjust nr
115 do idir = 1, space%dim
116 chi = m_zero
117 ! the upper border
118 jj = 0
119 out = .false.
120 do while(.not.out)
121 jj = jj + 1
122 chi(idir) = real(jj, real64) * mesh%spacing(idir)
123 if (mesh%use_curvilinear) then
124 x = coord_system%to_cartesian(chi)
125 out = x(idir) > maxval(abs(box_bounds(:, idir))) + box_boundary_delta
126 else
127 ! do the same comparison here as in simul_box_contains_points
128 out = chi(idir) > maxval(abs(box_bounds(:, idir))) + box_boundary_delta
129 end if
130 end do
131 mesh%idx%nr(2, idir) = jj - 1
132 end do
133
134 ! we have a symmetric mesh (for now)
135 mesh%idx%nr(1,:) = -mesh%idx%nr(2,:)
136
137 ! we have to adjust a couple of things for the periodic directions
138 do idir = 1, space%periodic_dim
139 if (mesh%idx%nr(2, idir) == 0) then
140 ! this happens if Spacing > box size
141 mesh%idx%nr(2, idir) = 1
142 mesh%idx%nr(1, idir) = -1
143 end if
144
145 ! We have to adjust the spacing to be commensurate with the box,
146 ! for this we scan the possible values of the grid size around the
147 ! one we selected. We choose the size that has the spacing closest
148 ! to the requested one.
149 do delta = -1, 1
150 spacing_new(delta) = m_two*maxval(abs(box_bounds(:, idir))) / real(2 * mesh%idx%nr(2, idir) + 1 - delta, real64)
151 spacing_new(delta) = abs(spacing_new(delta) - spacing(idir))
152 end do
153
154 delta = minloc(spacing_new, dim = 1) - 2
155
156 assert(delta >= -1)
157 assert(delta <= 1)
158
159 mesh%spacing(idir) = m_two*maxval(abs(box_bounds(:, idir))) / real(2 * mesh%idx%nr(2, idir) + 1 - delta, real64)
161 ! we need to adjust the grid by adding or removing one point
162 if (delta == -1) then
163 mesh%idx%nr(1, idir) = mesh%idx%nr(1, idir) - 1
164 else if (delta == 1) then
165 mesh%idx%nr(2, idir) = mesh%idx%nr(2, idir) - 1
166 end if
167
168 end do
169
170 if ( any(abs(mesh%spacing - spacing) > 1.e-6_real64) ) then
171 call messages_write('The spacing has been modified to make it commensurate with the periodicity of the system.')
172 call messages_warning()
173 end if
174
175 do idir = space%periodic_dim + 1, space%dim
176 if (mesh%idx%nr(2, idir) == 0) then
177 write(message(1),'(a,i2)') 'Spacing > box size in direction ', idir
178 call messages_fatal(1, namespace=namespace)
179 end if
180 end do
181
182 mesh%idx%ll = mesh%idx%nr(2, :) - mesh%idx%nr(1, :) + 1
183 ! compute strides for cubic indices
184 mesh%idx%stride(:) = 1
185 do idir = 2, space%dim+1
186 mesh%idx%stride(idir) = mesh%idx%stride(idir-1) * &
187 (mesh%idx%ll(idir-1) + 2*mesh%idx%enlarge(idir-1))
188 end do
189
190 pop_sub_with_profile(mesh_init_stage_1)
191 end subroutine mesh_init_stage_1
192
193 ! ---------------------------------------------------------
199 !
200 subroutine mesh_init_stage_2(mesh, namespace, space, box, stencil, grp, regenerate)
201 class(mesh_t), intent(inout) :: mesh
202 type(namespace_t), intent(in) :: namespace
203 class(space_t), intent(in) :: space
204 class(box_t), intent(in) :: box
205 type(stencil_t), intent(in) :: stencil
206 type(mpi_grp_t), intent(in) :: grp
207 logical, optional, intent(in) :: regenerate
208
209 integer :: is
210 real(real64) :: chi(1:space%dim)
211 real(real64) :: pos(space%dim)
212 integer :: point(space%dim), point_stencil(space%dim), grid_sizes(space%dim)
213 integer(int64) :: global_size
214 integer(int32) :: local_size
215 integer(int64) :: ispatial, ispatialb, istart, iend, spatial_size, ipg
216 integer :: ip, ib, ib2, np, np_boundary, ii
217 logical :: found
218 type(lihash_t) :: spatial_to_boundary
219 integer(int64), allocatable :: boundary_to_spatial(:), boundary_to_spatial_reordered(:)
220 integer(int64), allocatable :: grid_to_spatial(:), grid_to_spatial_initial(:), grid_to_spatial_reordered(:)
221 integer(int64), allocatable :: spatial_to_grid(:)
222 integer, allocatable :: sizes(:)
223 integer(int64), allocatable :: offsets(:)
224 integer :: size_boundary
225#ifdef HAVE_MPI
226 integer(int64), pointer :: ptr(:)
227 type(mpi_grp_t) :: internode_grp, intranode_grp
228#endif
229
230 push_sub_with_profile(mesh_init_stage_2)
231
232 if (.not. optional_default(regenerate, .false.)) then
233 ! enlarge mesh for boundary points
234 mesh%idx%nr(1, :) = mesh%idx%nr(1, :) - mesh%idx%enlarge(:)
235 mesh%idx%nr(2, :) = mesh%idx%nr(2, :) + mesh%idx%enlarge(:)
236 end if
237
238 !%Variable MeshIndexType
239 !%Type integer
240 !%Default idx_cubic
241 !%Section Mesh
242 !%Description
243 !% Determine index type. Must be the same for restarting a calculation.
244 !%Option idx_cubic 1
245 !% Cubic indices are used to map the spatial information to the grid points.
246 !%Option idx_hilbert 2
247 !% A Hilbert space-filling curve is used to map the spatial information to
248 !% the grid points.
249 !%End
250 call parse_variable(namespace, 'MeshIndexType', idx_cubic, mesh%idx%type)
251
252 grid_sizes = mesh%idx%nr(2, :) - mesh%idx%nr(1, :) + 1
253 mesh%idx%offset = grid_sizes/2
254 if (space%dim > 1 .and. any(grid_sizes > 2**(int(63/space%dim, int64)))) then
255 write(message(1), '(A, I10, A, I2, A)') "Error: grid too large, more than ", 2**(int(63/space%dim, int64)), &
256 " points in one direction for ", space%dim, " dimensions. This is not supported."
257 call messages_fatal(1, namespace=namespace)
258 end if
259 global_size = product(int(grid_sizes, int64))
260 ! compute the bits per dimension: grid_sizes(i) <= 2**bits
261 mesh%idx%bits = maxval(ceiling(log(real(grid_sizes, real64) )/log(2.0_real64)))
262
263 if (mesh%idx%type == idx_cubic) then
264 spatial_size = global_size
265 else if (mesh%idx%type == idx_hilbert) then
266 spatial_size = 2**(space%dim*mesh%idx%bits)
267 end if
268
269 ! use block data decomposition of spatial indices
270 istart = spatial_size * grp%rank/grp%size
271 iend = spatial_size * (grp%rank+1)/grp%size - 1
272 if (.not. (iend - istart + 1 < huge(0_int32))) then
273 write(message(1), '(A, I10, A, I2, A)') "Error: local grid too large, more than ", &
274 huge(0_int32), " points. This is not supported. Maybe use more MPI ranks?"
275 call messages_fatal(1, namespace=namespace)
276 end if
277 local_size = int(iend - istart + 1, int32)
278
279 safe_allocate(grid_to_spatial_initial(1:local_size))
280
281 ! get inner grid indices
282 ip = 1
283 do ispatial = istart, iend
284 call index_spatial_to_point(mesh%idx, space%dim, ispatial, point)
285 ! first check if point is outside bounding box
286 if (any(point < mesh%idx%nr(1, :) + mesh%idx%enlarge)) cycle
287 if (any(point > mesh%idx%nr(2, :) - mesh%idx%enlarge)) cycle
288 ! then check if point is inside simulation box
289 chi = real(point, real64) * mesh%spacing
290 pos = mesh%coord_system%to_cartesian(chi)
291 if (.not. box%contains_point(pos)) cycle
292 grid_to_spatial_initial(ip) = ispatial
293 assert(ip + 1 < huge(ip))
294 ip = ip + 1
295 end do
296 np = ip - 1
297
298 call rebalance_array(grp,grid_to_spatial_initial(1:np), grid_to_spatial, sizes)
299 np = sizes(grp%rank)
300
301 safe_deallocate_a(grid_to_spatial_initial)
302
303 safe_allocate(spatial_to_grid(grid_to_spatial(1):grid_to_spatial(np)))
304 safe_deallocate_a(sizes)
305
306 !$omp parallel do
307 do ispatial = grid_to_spatial(1), grid_to_spatial(np)
308 spatial_to_grid(ispatial) = -1
309 end do
310 !$omp parallel do
311 do ip = 1, np
312 spatial_to_grid(grid_to_spatial(ip)) = ip
313 end do
314
315 ! get local boundary indices
316 call lihash_init(spatial_to_boundary)
317 size_boundary = np
318 safe_allocate(boundary_to_spatial(1:size_boundary))
319 ib = 1
320 do ip = 1, np
321 call index_spatial_to_point(mesh%idx, space%dim, grid_to_spatial(ip), point)
322 do is = 1, stencil%size
323 if (stencil%center == is) cycle
324 point_stencil(1:space%dim) = point(1:space%dim) + stencil%points(1:space%dim, is)
325 ! check if point is in inner part
326 call index_point_to_spatial(mesh%idx, space%dim, ispatialb, point_stencil)
327 assert(ispatialb >= 0)
328 if (ispatialb >= lbound(spatial_to_grid, dim=1, kind=int64) .and. &
329 ispatialb <= ubound(spatial_to_grid, dim=1, kind=int64)) then
330 if (spatial_to_grid(ispatialb) > 0) cycle
331 end if
332 ! then check if point is inside simulation box
333 chi = real(point_stencil, real64) * mesh%spacing
334 pos = mesh%coord_system%to_cartesian(chi)
335 if (box%contains_point(pos)) cycle
336 ! it has to be a boundary point now
337 ! check if already counted
338 ib2 = lihash_lookup(spatial_to_boundary, ispatialb, found)
339 if (found) cycle
340 boundary_to_spatial(ib) = ispatialb
341 call lihash_insert(spatial_to_boundary, ispatialb, ib)
342 ib = ib + 1
343 ! enlarge array
344 if (ib >= size_boundary) then
345 size_boundary = size_boundary * 2
346 call make_array_larger(boundary_to_spatial, size_boundary)
347 end if
348 end do
349 end do
350 np_boundary = ib - 1
351 call lihash_end(spatial_to_boundary)
352 safe_deallocate_a(spatial_to_grid)
353
354 ! reorder inner points
355 call reorder_points(namespace, space, grp, mesh%idx, grid_to_spatial, grid_to_spatial_reordered)
356 safe_deallocate_a(grid_to_spatial)
357
358 call rebalance_array(grp,grid_to_spatial_reordered, grid_to_spatial, sizes)
359 np = sizes(grp%rank)
360 mesh%np_global = sizes(0)
361 do ii = 1, grp%size - 1
362 mesh%np_global = mesh%np_global + sizes(ii)
363 end do
364 safe_deallocate_a(sizes)
365 safe_deallocate_a(grid_to_spatial_reordered)
366
367 ! reorder boundary points
368 call make_array_larger(boundary_to_spatial, np_boundary)
369 call reorder_points(namespace, space, grp, mesh%idx, boundary_to_spatial, boundary_to_spatial_reordered)
370 safe_deallocate_a(boundary_to_spatial)
371
372 call rebalance_array(grp,boundary_to_spatial_reordered, boundary_to_spatial, sizes)
373 safe_deallocate_a(boundary_to_spatial_reordered)
374
375 ! global grid size
376 np_boundary = sizes(grp%rank)
377 mesh%np_part_global = mesh%np_global + sizes(0)
378 do ii = 1, grp%size - 1
379 mesh%np_part_global = mesh%np_part_global + sizes(ii)
380 end do
381 safe_deallocate_a(sizes)
382
383
384 ! get global indices
385#ifdef HAVE_MPI
386 ! create shared memory window and fill it only on root
387 call create_intranode_communicator(grp, intranode_grp, internode_grp)
388 call lmpi_create_shared_memory_window(mesh%np_part_global, intranode_grp, &
389 mesh%idx%window_grid_to_spatial, mesh%idx%grid_to_spatial_global)
390#else
391 safe_allocate(mesh%idx%grid_to_spatial_global(1:mesh%np_part_global))
392#endif
393 ! inner grid
394 call get_sizes_offsets(np, sizes, offsets, grp)
395 call grp%gatherv(grid_to_spatial, np, mpi_integer8, &
396 mesh%idx%grid_to_spatial_global, sizes, offsets, mpi_integer8, 0)
397
398 ! boundary indices
399 call get_sizes_offsets(np_boundary, sizes, offsets, grp)
400 call grp%gatherv(boundary_to_spatial, np_boundary, mpi_integer8, &
401 mesh%idx%grid_to_spatial_global(mesh%np_global+1:), sizes, offsets, mpi_integer8, 0)
402
403 ! fill global hash map
404#ifdef HAVE_MPI
405 ! create shared memory window and fill it only on root
406 call lmpi_create_shared_memory_window(spatial_size, intranode_grp, &
407 mesh%idx%window_spatial_to_grid, ptr)
408 mesh%idx%spatial_to_grid_global(0:spatial_size-1) => ptr(1:spatial_size)
409#else
410 safe_allocate(mesh%idx%spatial_to_grid_global(0:spatial_size-1))
411#endif
412 if (grp%is_root()) then
413 ! fill only on root, then broadcast
414 !$omp parallel do
415 do ispatial = 0, spatial_size-1
416 mesh%idx%spatial_to_grid_global(ispatial) = 0
417 end do
418 !$omp parallel do
419 do ipg = 1, mesh%np_part_global
420 mesh%idx%spatial_to_grid_global(mesh%idx%grid_to_spatial_global(ipg)) = ipg
421 end do
422 end if
423
424#ifdef HAVE_MPI
425 ! now broadcast the global arrays to local rank 0 on each node
426 if (intranode_grp%is_root()) then
427 call internode_grp%bcast(mesh%idx%grid_to_spatial_global(1), mesh%np_part_global, mpi_integer8, 0)
428 call internode_grp%bcast(mesh%idx%spatial_to_grid_global(0), spatial_size, mpi_integer8, 0)
429 end if
430 call lmpi_sync_shared_memory_window(mesh%idx%window_grid_to_spatial, intranode_grp)
431 call lmpi_sync_shared_memory_window(mesh%idx%window_spatial_to_grid, intranode_grp)
432#endif
433
434 safe_deallocate_a(offsets)
435 safe_deallocate_a(sizes)
436
437 safe_deallocate_a(boundary_to_spatial)
438 safe_deallocate_a(grid_to_spatial)
439
440 pop_sub_with_profile(mesh_init_stage_2)
441 end subroutine mesh_init_stage_2
442
443! ---------------------------------------------------------
448! ---------------------------------------------------------
449 subroutine mesh_init_stage_3(mesh, namespace, space, stencil, mc, parent, regenerate)
450 class(mesh_t), intent(inout) :: mesh
451 type(namespace_t), intent(in) :: namespace
452 class(space_t), intent(in) :: space
453 type(stencil_t), intent(in) :: stencil
454 type(multicomm_t), intent(in) :: mc
455 type(mesh_t), optional, intent(in) :: parent
456 logical, optional, intent(in) :: regenerate
457
458 integer :: ip, jj(space%dim), np
459
460 push_sub_with_profile(mesh_init_stage_3)
461
462 call mpi_grp_init(mesh%mpi_grp, mc%group_comm(p_strategy_domains))
463
464 ! check if we are running in parallel in domains
465 mesh%parallel_in_domains = (mesh%mpi_grp%size > 1)
466
467 call checksum_calculate(1, mesh%np_part_global, mesh%idx%grid_to_spatial_global(1), &
468 mesh%idx%checksum)
469
470 if (mesh%parallel_in_domains) then
471 call do_partition()
472 else
473 ! When running serially those two are the same.
474 assert(mesh%np_part_global < huge(mesh%np_part))
475 mesh%np = i8_to_i4(mesh%np_global)
476 mesh%np_part = i8_to_i4(mesh%np_part_global)
477
478 ! These must be initialized for par_vec_gather, par_vec_scatter to work
479 ! as copy operations when running without domain parallelization.
480 mesh%pv%np_global = mesh%np_global
481 mesh%pv%np_ghost = 0
482 mesh%pv%np_bndry = mesh%np_part - mesh%np
483 mesh%pv%npart = 1
484 mesh%pv%xlocal = 1
485 end if
486
487 ! Compute mesh%x
488 safe_allocate(mesh%x(1:space%dim, 1:mesh%np_part))
489 safe_allocate(mesh%x_t(1:mesh%np_part, 1:space%dim))
490 do ip = 1, mesh%np_part
491 mesh%x(1:space%dim, ip) = mesh_x_global(mesh, mesh_local2global(mesh, ip))
492 mesh%x_t(ip, 1:space%dim) = mesh%x(1:space%dim, ip)
493 end do
494
495 ! save chi, i.e. primitive coordinates
496 safe_allocate(mesh%chi(1:space%dim, 1:mesh%np_part))
497 do ip = 1, mesh%np_part
498 call mesh_local_index_to_coords(mesh, ip, jj)
499 mesh%chi(:, ip) = jj*mesh%spacing
500 end do
501
502 call mesh_get_vol_pp()
503
504 ! save inverse jacobian
505 if (mesh%coord_system%local_basis) then
506 np = mesh%np_part
507 else
508 np = 1
509 end if
510 safe_allocate(mesh%jacobian_inverse(1:space%dim, 1:space%dim, np))
511 do ip = 1, np
512 mesh%jacobian_inverse(:, :, ip) = mesh%coord_system%jacobian_inverse(mesh%chi(:, ip))
513 end do
514
515 pop_sub_with_profile(mesh_init_stage_3)
516
517 contains
518 ! ---------------------------------------------------------
519 subroutine do_partition()
520#ifdef HAVE_MPI
521 integer :: jj, ipart, jpart
522 integer(int64) :: ipg, jpg
523 integer, allocatable :: gindex(:), gedges(:)
524 logical, allocatable :: nb(:, :)
525 integer :: idx(space%dim), jx(space%dim)
526 type(mpi_comm) :: graph_comm
527 integer :: iedge, nnb
528 logical :: use_topo, reorder, partition_print
529 integer :: ierr
530
531 logical :: has_virtual_partition = .false.
532 integer :: vsize
533 type(restart_t) :: restart_load, restart_dump
534 integer, allocatable :: part_vec(:)
535
537
538 !Try to load the partition from the restart files
539 if (.not. optional_default(regenerate, .false.)) then
540 call restart_load%init(namespace, restart_partition, restart_type_load, mc, ierr, mesh=mesh, exact=.true.)
541 if (ierr == 0) call mesh_partition_load(restart_load, mesh, ierr)
542 call restart_load%end()
543 else
544 ierr = 0
545 end if
546
547 if (ierr /= 0) then
548
549 !%Variable MeshPartitionVirtualSize
550 !%Type integer
551 !%Default mesh mpi_grp size
552 !%Section Execution::Parallelization
553 !%Description
554 !% Gives the possibility to change the partition nodes.
555 !% Afterward, it crashes.
556 !%End
557 call parse_variable(namespace, 'MeshPartitionVirtualSize', mesh%mpi_grp%size, vsize)
558
559 if (vsize /= mesh%mpi_grp%size) then
560 write(message(1),'(a,I7)') "Changing the partition size to", vsize
561 write(message(2),'(a)') "The execution will crash."
562 call messages_warning(2, namespace=namespace)
563 has_virtual_partition = .true.
564 else
565 has_virtual_partition = .false.
566 end if
567
568 if (.not. present(parent)) then
569 call mesh_partition(mesh, namespace, space, stencil, vsize)
570 else
571 ! if there is a parent grid, use its partition
572 call mesh_partition_from_parent(mesh, parent)
573 end if
574
575 !Now that we have the partitions, we save them
576 call restart_dump%init(namespace, restart_partition, restart_type_dump, mc, ierr, mesh=mesh)
577 call mesh_partition_dump(restart_dump, mesh, vsize, ierr)
578 call restart_dump%end()
579 end if
580
581 if (has_virtual_partition) then
582 call profiling_end(namespace)
583 call print_date("Calculation ended on ")
584 write(message(1),'(a)') "Execution has ended."
585 write(message(2),'(a)') "If you want to run your system, do not use MeshPartitionVirtualSize."
586 call messages_warning(2, namespace=namespace)
587 call messages_end()
588 call global_end()
589 stop
590 end if
591
592 !%Variable MeshUseTopology
593 !%Type logical
594 !%Default false
595 !%Section Execution::Parallelization
596 !%Description
597 !% (experimental) If enabled, <tt>Octopus</tt> will use an MPI virtual
598 !% topology to map the processors. This can improve performance
599 !% for certain interconnection systems.
600 !%End
601 call parse_variable(namespace, 'MeshUseTopology', .false., use_topo)
602
603 if (use_topo) then
604 ! At the moment we still need the global partition. This will be removed in near future.
605 safe_allocate(part_vec(1:mesh%np_global))
606 call partition_get_global(mesh%partition, part_vec(1:mesh%np_global))
607
608
609 ! generate a table of neighbours
610
611 safe_allocate(nb(1:mesh%mpi_grp%size, 1:mesh%mpi_grp%size))
612 nb = .false.
613
614 do ipg = 1, mesh%np_global
615 ipart = part_vec(ipg)
616 call mesh_global_index_to_coords(mesh, ipg, idx)
617 do jj = 1, stencil%size
618 jx = idx + stencil%points(:, jj)
619 jpg = mesh_global_index_from_coords(mesh, jx)
620 if (jpg > 0 .and. jpg <= mesh%np_global) then
621 jpart = part_vec(jpg)
622 if (ipart /= jpart ) nb(ipart, jpart) = .true.
623 end if
624 end do
625 end do
626 safe_deallocate_a(part_vec)
627
628 ! now generate the information of the graph
629
630 safe_allocate(gindex(1:mesh%mpi_grp%size))
631 safe_allocate(gedges(1:count(nb)))
632
633 ! and now generate it
634 iedge = 0
635 do ipart = 1, mesh%mpi_grp%size
636 do jpart = 1, mesh%mpi_grp%size
637 if (nb(ipart, jpart)) then
638 iedge = iedge + 1
639 gedges(iedge) = jpart - 1
640 end if
641 end do
642 gindex(ipart) = iedge
643 end do
644
645 assert(iedge == count(nb))
646
647 reorder = .true.
648 call mpi_graph_create(mesh%mpi_grp%comm, mesh%mpi_grp%size, gindex, gedges, reorder, graph_comm)
649
650 ! we have a new communicator
651 call mpi_grp_init(mesh%mpi_grp, graph_comm)
652
653 safe_deallocate_a(nb)
654 safe_deallocate_a(gindex)
655 safe_deallocate_a(gedges)
656
657 end if
659 if (optional_default(regenerate, .false.)) call par_vec_end(mesh%pv)
660 call par_vec_init(mesh%mpi_grp, mesh%np_global, mesh%idx, stencil,&
661 space, mesh%partition, mesh%pv, namespace)
662
663 ! check the number of ghost neighbours in parallel
664 nnb = 0
665 jpart = mesh%pv%partno
666 do ipart = 1, mesh%pv%npart
667 if (ipart == jpart) cycle
668 if (mesh%pv%ghost_scounts(ipart) /= 0) nnb = nnb + 1
669 end do
670 assert(nnb >= 0 .and. nnb < mesh%pv%npart)
671
672 ! Set local point numbers.
673 mesh%np = mesh%pv%np_local
674 mesh%np_part = mesh%np + mesh%pv%np_ghost + mesh%pv%np_bndry
675
676 !%Variable PartitionPrint
677 !%Type logical
678 !%Default true
679 !%Section Execution::Parallelization
680 !%Description
681 !% (experimental) If disabled, <tt>Octopus</tt> will not compute
682 !% nor print the partition information, such as local points,
683 !% no. of neighbours, ghost points and boundary points.
684 !%End
685 call parse_variable(namespace, 'PartitionPrint', .true., partition_print)
686
687 if (partition_print) then
688 call mesh_partition_write_info(mesh, namespace=namespace)
689 call mesh_partition_messages_debug(mesh, namespace)
690 end if
691#endif
692
694 end subroutine do_partition
695
696
697 ! ---------------------------------------------------------
699 subroutine mesh_get_vol_pp()
700
701 integer :: ip, np
702
704
705 np = 1
706 if (mesh%use_vol_pp) np = mesh%np_part
707 ! If no local point, we should not try to access the arrays
708 if (mesh%np_part == 0) np = 0
709
710 safe_allocate(mesh%vol_pp(1:np))
711
712 do ip = 1, np
713 mesh%vol_pp(ip) = product(mesh%spacing)
714 end do
715
716 do ip = 1, np
717 mesh%vol_pp(ip) = mesh%vol_pp(ip)*mesh%coord_system%jacobian_determinant(mesh%chi(:, ip))
718 end do
719
720 if (mesh%use_vol_pp .or. mesh%np_part == 0) then
721 mesh%volume_element = m_one
722 else
723 mesh%volume_element = mesh%vol_pp(1)
724 end if
725
726 ! the weights on the device, for weighted reductions of device batches
727 if (mesh%use_vol_pp .and. accel_is_enabled()) then
728 call accel_create_buffer(mesh%vol_pp_buffer, accel_mem_read_only, type_float, max(np, 1))
729 call accel_create_buffer(mesh%sqrt_vol_pp_buffer, accel_mem_read_only, type_float, max(np, 1))
730 if (np > 0) then
731 call accel_write_buffer(mesh%vol_pp_buffer, np, mesh%vol_pp)
732 call accel_write_buffer(mesh%sqrt_vol_pp_buffer, np, sqrt(mesh%vol_pp))
733 end if
734 end if
735
737 end subroutine mesh_get_vol_pp
738
739 end subroutine mesh_init_stage_3
740
745 subroutine rebalance_array(grp, data_input, data_output, output_sizes)
746 type(mpi_grp_t), intent(in) :: grp
747 integer(int64), contiguous, intent(in) :: data_input(:)
748 integer(int64), allocatable, intent(out) :: data_output(:)
749 integer, allocatable, optional, intent(out) :: output_sizes(:)
750
751 integer, allocatable :: initial_sizes(:), final_sizes(:)
752 integer(int64), allocatable :: initial_offsets(:), final_offsets(:)
753 integer, allocatable :: scounts(:), sdispls(:)
754 integer, allocatable :: rcounts(:), rdispls(:)
755 integer :: irank
756 integer(int64) :: itmp
757
758 push_sub(rebalance_array)
759
760 ! collect current sizes of distributed array
761 safe_allocate(initial_sizes(0:grp%size-1))
762 call grp%allgather(size(data_input), 1, mpi_integer, initial_sizes(0), 1, mpi_integer)
763 safe_allocate(initial_offsets(0:grp%size))
764 initial_offsets(0) = 0
765 do irank = 1, grp%size
766 initial_offsets(irank) = initial_offsets(irank-1) + initial_sizes(irank-1)
767 end do
768
769 ! now redistribute the arrays
770 ! use block data decomposition of grid indices
771 safe_allocate(final_offsets(0:grp%size))
772 safe_allocate(final_sizes(0:grp%size-1))
773
774 do irank = 0, grp%size
775 final_offsets(irank) = sum(int(initial_sizes, int64)) * irank/grp%size
776 end do
777 do irank = 0, grp%size - 1
778 assert(final_offsets(irank + 1) - final_offsets(irank) < huge(0_int32))
779 final_sizes(irank) = int(final_offsets(irank + 1) - final_offsets(irank), int32)
780 end do
781
782 safe_allocate(scounts(0:grp%size-1))
783 safe_allocate(sdispls(0:grp%size-1))
784 safe_allocate(rcounts(0:grp%size-1))
785 safe_allocate(rdispls(0:grp%size-1))
786 ! determine communication pattern
787 scounts = 0
788 do irank = 0, grp%size - 1
789 ! get overlap of initial and final distribution
790 itmp = min(final_offsets(irank+1), initial_offsets(grp%rank+1)) - &
791 max(final_offsets(irank), initial_offsets(grp%rank))
792 assert(itmp < huge(0_int32))
793 if (itmp < 0) then
794 scounts(irank) = 0
795 else
796 scounts(irank) = int(itmp, int32)
797 end if
798 end do
799 sdispls(0) = 0
800 do irank = 1, grp%size - 1
801 sdispls(irank) = sdispls(irank - 1) + scounts(irank - 1)
802 end do
803 assert(sum(int(scounts, int64)) < huge(0_int32))
804 assert(sum(scounts) == initial_sizes(grp%rank))
805
806 rcounts = 0
807 do irank = 0, grp%size - 1
808 ! get overlap of initial and final distribution
809 itmp = min(final_offsets(grp%rank+1), initial_offsets(irank+1)) - &
810 max(final_offsets(grp%rank), initial_offsets(irank))
811 assert(itmp < huge(0_int32))
812 if (itmp < 0) then
813 rcounts(irank) = 0
814 else
815 rcounts(irank) = int(itmp, int32)
816 end if
817 end do
818 rdispls(0) = 0
819 do irank = 1, grp%size - 1
820 rdispls(irank) = rdispls(irank - 1) + rcounts(irank - 1)
821 end do
822 ! check for consistency between sending and receiving
823 assert(sum(rcounts) == final_sizes(grp%rank))
824
825 safe_allocate(data_output(1:final_sizes(grp%rank)))
826 call grp%alltoallv(data_input, scounts, sdispls, mpi_integer8, &
827 data_output, rcounts, rdispls, mpi_integer8)
828
829 ! save final sizes of array if optional argument present
830 if (present(output_sizes)) then
831 safe_allocate(output_sizes(0:grp%size-1))
832 output_sizes(:) = final_sizes(:)
833 end if
834
835 safe_deallocate_a(final_offsets)
836 safe_deallocate_a(final_sizes)
837
838 safe_deallocate_a(scounts)
839 safe_deallocate_a(sdispls)
840 safe_deallocate_a(rcounts)
841 safe_deallocate_a(rdispls)
842
843
844 pop_sub(rebalance_array)
845 end subroutine rebalance_array
846
851 subroutine reorder_points(namespace, space, grp, idx, grid_to_spatial, grid_to_spatial_reordered)
852 type(namespace_t), intent(in) :: namespace
853 class(space_t), intent(in) :: space
854 type(mpi_grp_t), intent(in) :: grp
855 type(index_t), intent(in) :: idx
856 integer(int64), contiguous, intent(in) :: grid_to_spatial(:)
857 integer(int64), allocatable, intent(out) :: grid_to_spatial_reordered(:)
858
859 integer :: bsize(space%dim), order, default
860 integer :: nn, idir, ipg, ip, number_of_blocks(space%dim)
861 type(block_t) :: blk
862 integer, parameter :: &
863 ORDER_BLOCKS = 1, &
864 order_original = 2, &
865 order_cube = 3
866 integer :: point(1:space%dim)
867 integer(int64), allocatable :: reorder_indices(:), reorder_recv(:)
868 integer, allocatable :: index_map(:), indices(:)
869 integer(int64), allocatable :: grid_to_spatial_recv(:)
870 integer, allocatable :: initial_sizes(:)
871 integer(int64), allocatable :: initial_offsets(:)
872 integer(int64) :: istart, iend, indstart, indend, spatial_size
873 integer :: irank, local_size, num_recv
874 integer :: iunique, nunique
875 integer :: direction
876 logical :: increase_with_dimension
877
878 integer, allocatable :: scounts(:), sdispls(:), rcounts(:), rdispls(:)
879 integer(int64), allocatable :: spatial_cutoff(:)
880
881 push_sub(reorder_points)
882
883 !%Variable MeshOrder
884 !%Type integer
885 !%Section Execution::Optimization
886 !%Description
887 !% This variable controls how the grid points are mapped to a
888 !% linear array for global arrays. For runs that are parallel
889 !% in domains, the local mesh order may be different (see
890 !% <tt>MeshLocalOrder</tt>).
891 !% The default is blocks when serial in domains and cube when
892 !% parallel in domains with the local mesh order set to blocks.
893 !%Option order_blocks 1
894 !% The grid is mapped using small parallelepipedic grids. The size
895 !% of the blocks is controlled by <tt>MeshBlockSize</tt>.
896 !%Option order_original 2
897 !% The original order of the indices is used to map the grid.
898 !%Option order_cube 3
899 !% The grid is mapped using a full cube, i.e. without blocking.
900 !%End
901 default = order_blocks
902 call parse_variable(namespace, 'MeshOrder', default, order)
903 ! no reordering in 1D necessary
904 if (space%dim == 1) then
905 order = order_original
906 end if
907
908 !%Variable MeshBlockDirection
909 !%Type integer
910 !%Section Execution::Optimization
911 !%Description
912 !% Determines the direction in which the dimensions are chosen to compute
913 !% the blocked index for sorting the mesh points (see MeshBlockSize).
914 !% The default is increase_with_dimensions, corresponding to xyz ordering
915 !% in 3D.
916 !%Option increase_with_dimension 1
917 !% The fastest changing index is in the first dimension, i.e., in 3D this
918 !% corresponds to ordering in xyz directions.
919 !%Option decrease_with_dimension 2
920 !% The fastest changing index is in the last dimension, i.e., in 3D this
921 !% corresponds to ordering in zyx directions.
922 !%End
923 call parse_variable(namespace, 'MeshBlockDirection', 1, direction)
924 increase_with_dimension = direction == 1
925 if (direction /= 1 .and. direction /= 2) then
926 call messages_input_error(namespace, 'MeshBlockDirection')
927 end if
928
929 select case (order)
930 case (order_original)
931 ! only copy points, they stay in their original ordering
932 safe_allocate(grid_to_spatial_reordered(1:size(grid_to_spatial)))
933 grid_to_spatial_reordered(1:size(grid_to_spatial)) = grid_to_spatial(1:size(grid_to_spatial))
934 case (order_blocks, order_cube)
935 if (order == order_cube) then
936 bsize = idx%nr(2, :) - idx%nr(1, :) + 1
937 else
938 !%Variable MeshBlockSize
939 !%Type block
940 !%Section Execution::Optimization
941 !%Description
942 !% To improve memory-access locality when calculating derivatives,
943 !% <tt>Octopus</tt> arranges mesh points in blocks. This variable
944 !% controls the size of this blocks in the different
945 !% directions. The default is selected according to the value of
946 !% the <tt>StatesBlockSize</tt> variable. (This variable only affects the
947 !% performance of <tt>Octopus</tt> and not the results.)
948 !%End
949 if (conf%target_states_block_size < 16) then
950 bsize(1) = 80 * 4 / abs(conf%target_states_block_size)
951 if (space%dim > 1) bsize(2) = 4
952 if (space%dim > 2) bsize(3:) = 10
953 else
954 bsize(1) = max(4 * 16 / abs(conf%target_states_block_size), 1)
955 if (space%dim > 1) bsize(2) = 15
956 if (space%dim > 2) bsize(3:) = 15
957 end if
958
959 if (parse_block(namespace, 'MeshBlockSize', blk) == 0) then
960 nn = parse_block_cols(blk, 0)
961 if (nn /= space%dim) then
962 message(1) = "Error: number of entries in MeshBlockSize must match the number of dimensions."
963 call messages_fatal(1, namespace=namespace)
964 end if
965 do idir = 1, nn
966 call parse_block_integer(blk, 0, idir - 1, bsize(idir))
967 end do
968 end if
969 end if
970
971 number_of_blocks = (idx%nr(2, :) - idx%nr(1, :) + 1) / bsize + 1
972
973
974 ! do the global reordering in parallel, use block data decomposition of global indices
975 ! reorder indices along blocked parallelepiped curve
976
977 ! collect current sizes of distributed array
978 safe_allocate(initial_sizes(0:grp%size-1))
979 call grp%allgather(size(grid_to_spatial), 1, mpi_integer, initial_sizes(0), 1, mpi_integer)
980 safe_allocate(initial_offsets(0:grp%size))
981 initial_offsets(0) = 0
982 do irank = 1, grp%size
983 initial_offsets(irank) = initial_offsets(irank-1) + initial_sizes(irank-1)
984 end do
985
986 ! get local range and size
987 istart = initial_offsets(grp%rank)
988 iend = initial_offsets(grp%rank + 1) - 1
989 assert(iend - istart + 1 < huge(0_int32))
990 local_size = int(iend - istart + 1, int32)
991 assert(local_size == initial_sizes(grp%rank))
992
993 ! compute new indices locally
994 safe_allocate(reorder_indices(1:local_size))
995 safe_allocate(indices(1:local_size))
996 safe_allocate(grid_to_spatial_reordered(1:local_size))
997 !$omp parallel do private(point)
998 do ip = 1, local_size
999 call index_spatial_to_point(idx, space%dim, grid_to_spatial(ip), point)
1000 point = point + idx%offset
1001 reorder_indices(ip) = get_blocked_index(space%dim, point, bsize, number_of_blocks, increase_with_dimension)
1002 end do
1003 ! parallel sort according to the new indices
1004 ! sort the local array
1005 call sort(reorder_indices, indices)
1006 ! save reordered indices to send to other processes
1007 !$omp parallel do
1008 do ip = 1, local_size
1009 grid_to_spatial_reordered(ip) = grid_to_spatial(indices(ip))
1010 end do
1011
1012 ! get minimum and maximum
1013 if(local_size > 0) then
1014 indstart = reorder_indices(1)
1015 indend = reorder_indices(local_size)
1016 else
1017 indstart = huge(1_int64)
1018 indend = 0
1019 end if
1020 call grp%allreduce_inplace(indstart, 1, mpi_integer8, mpi_min)
1021 call grp%allreduce_inplace(indend, 1, mpi_integer8, mpi_max)
1022 spatial_size = indend - indstart + 1
1023
1024 ! get index ranges for each rank
1025 safe_allocate(spatial_cutoff(0:grp%size-1))
1026 do irank = 0, grp%size - 1
1027 spatial_cutoff(irank) = spatial_size * (irank+1)/grp%size + indstart
1028 end do
1029
1030 safe_allocate(scounts(0:grp%size-1))
1031 safe_allocate(sdispls(0:grp%size-1))
1032 safe_allocate(rcounts(0:grp%size-1))
1033 safe_allocate(rdispls(0:grp%size-1))
1034 ! get send counts
1035 scounts = 0
1036 irank = 0
1037 ! the indices are ordered, so we can go through them and increase
1038 ! the rank to which they are associated to when we cross a cutoff
1039 do ip = 1, local_size
1040 if (reorder_indices(ip) >= spatial_cutoff(irank)) then
1041 ! this do loop is needed in case some ranks do not have any points
1042 do while (reorder_indices(ip) >= spatial_cutoff(irank))
1043 irank = irank + 1
1044 end do
1045 assert(irank < grp%size)
1046 end if
1047 scounts(irank) = scounts(irank) + 1
1048 end do
1049 safe_deallocate_a(spatial_cutoff)
1050 assert(sum(scounts) == local_size)
1051
1052 ! compute communication pattern (sdispls, rcounts, rdispls)
1053 sdispls(0) = 0
1054 do irank = 1, grp%size - 1
1055 sdispls(irank) = sdispls(irank - 1) + scounts(irank - 1)
1056 end do
1057
1058 call grp%alltoall(scounts, 1, mpi_integer, &
1059 rcounts, 1, mpi_integer)
1060
1061 rdispls(0) = 0
1062 do irank = 1, grp%size - 1
1063 rdispls(irank) = rdispls(irank - 1) + rcounts(irank - 1)
1064 end do
1065
1066 ! make sure the arrays get allocated also if we do not receive anything
1067 num_recv = max(sum(rcounts), 1)
1068 ! communicate the locally sorted indices
1069 safe_allocate(reorder_recv(1:num_recv))
1070 call grp%alltoallv(reorder_indices, scounts, sdispls, mpi_integer8, &
1071 reorder_recv, rcounts, rdispls, mpi_integer8)
1072 safe_deallocate_a(reorder_indices)
1073
1074 ! communicate the corresponding spatial indices
1075 safe_allocate(grid_to_spatial_recv(1:num_recv))
1076 call grp%alltoallv(grid_to_spatial_reordered, scounts, sdispls, mpi_integer8, &
1077 grid_to_spatial_recv, rcounts, rdispls, mpi_integer8)
1078 safe_deallocate_a(grid_to_spatial_reordered)
1079
1080 ! do k-way merge of sorted indices
1081 safe_allocate(reorder_indices(1:num_recv))
1082 safe_allocate(index_map(1:num_recv))
1083 if (sum(rcounts) > 0) then
1084 call merge_sorted_arrays(reorder_recv, rcounts, reorder_indices, index_map)
1085
1086 ! get number of unique indices, needed for boundary
1087 nunique = 1
1088 do ipg = 2, sum(rcounts)
1089 if (reorder_indices(ipg) /= reorder_indices(ipg-1)) then
1090 nunique = nunique + 1
1091 end if
1092 end do
1093
1094 ! reorder according to new order, but remove duplicate entries
1095 safe_allocate(grid_to_spatial_reordered(1:nunique))
1096 iunique = 1
1097 grid_to_spatial_reordered(iunique) = grid_to_spatial_recv(index_map(1))
1098 do ipg = 2, sum(rcounts)
1099 if (reorder_indices(ipg) /= reorder_indices(ipg-1)) then
1100 iunique = iunique + 1
1101 grid_to_spatial_reordered(iunique) = grid_to_spatial_recv(index_map(ipg))
1102 end if
1103 end do
1104 else
1105 safe_allocate(grid_to_spatial_reordered(1:0))
1106 end if
1107
1108 safe_deallocate_a(initial_offsets)
1109 safe_deallocate_a(initial_sizes)
1110
1111 safe_deallocate_a(reorder_indices)
1112 safe_deallocate_a(reorder_recv)
1113
1114 safe_deallocate_a(grid_to_spatial_recv)
1115 safe_deallocate_a(index_map)
1116 safe_deallocate_a(indices)
1117
1118 safe_deallocate_a(scounts)
1119 safe_deallocate_a(sdispls)
1120 safe_deallocate_a(rcounts)
1121 safe_deallocate_a(rdispls)
1122
1123 end select
1124 pop_sub(reorder_points)
1125 end subroutine reorder_points
1126
1129 subroutine get_sizes_offsets(local_size, sizes, offsets, mpi_grp)
1130 integer, intent(in) :: local_size
1131 integer, allocatable, intent(out) :: sizes(:)
1132 integer(int64), allocatable, intent(out) :: offsets(:)
1133 type(mpi_grp_t), intent(in) :: mpi_grp
1134
1135 integer :: irank
1136
1137 push_sub(get_sizes_offsets)
1138
1139 safe_allocate(sizes(0:mpi_grp%size-1))
1140 call mpi_grp%allgather(local_size, 1, mpi_integer, sizes(0), 1, mpi_integer)
1141 safe_allocate(offsets(0:mpi_grp%size))
1142 offsets(0) = 0
1143 do irank = 1, mpi_grp%size
1144 offsets(irank) = offsets(irank-1) + sizes(irank-1)
1145 end do
1146
1147 pop_sub(get_sizes_offsets)
1148 end subroutine get_sizes_offsets
1149
1150end module mesh_init_oct_m
1151
1152!! Local Variables:
1153!! mode: f90
1154!! coding: utf-8
1155!! End:
Box bounds along some axes.
Definition: box.F90:180
This is the common interface to a sorting routine. It performs the shell algorithm,...
Definition: sort.F90:156
double log(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
subroutine do_partition()
Definition: mesh_init.F90:605
subroutine mesh_get_vol_pp()
calculate the volume of integration
Definition: mesh_init.F90:613
pure logical function, public accel_is_enabled()
Definition: accel.F90:414
integer, parameter, public accel_mem_read_only
Definition: accel.F90:185
real(real64), parameter, public box_boundary_delta
Definition: box.F90:134
This module handles the calculation mode.
integer, parameter, public p_strategy_domains
parallelization in domains
real(real64), parameter, public m_two
Definition: global.F90:202
subroutine, public global_end()
Finalise parser varinfo file, and MPI.
Definition: global.F90:495
real(real64), parameter, public m_zero
Definition: global.F90:200
type(conf_t), public conf
Global instance of Octopus configuration.
Definition: global.F90:190
real(real64), parameter, public m_one
Definition: global.F90:201
This module implements a simple hash table for non-negative integer keys and integer values.
Definition: iihash.F90:127
integer function, public lihash_lookup(h, key, found)
Look up a value in the hash table h. If found is present, it indicates if key could be found in the t...
Definition: iihash.F90:336
subroutine, public lihash_insert(h, key, val)
Insert a (key, val) pair into the hash table h.
Definition: iihash.F90:310
subroutine, public lihash_end(h)
Free a hash table.
Definition: iihash.F90:288
subroutine, public lihash_init(h)
Initialize a hash table h.
Definition: iihash.F90:265
This module implements the index, used for the mesh points.
Definition: index.F90:124
subroutine, public index_init(idx, dim)
This subroutine allocates memory and initializes some components.
Definition: index.F90:220
integer(int64) function, public get_blocked_index(dim, point, bsize, number_of_blocks, increase_with_dimensions)
Definition: index.F90:499
subroutine, public index_spatial_to_point(idx, dim, ispatial, point)
Definition: index.F90:400
integer, parameter, public idx_hilbert
Definition: index.F90:169
subroutine, public index_point_to_spatial(idx, dim, ispatial, point)
Definition: index.F90:418
integer, parameter, public idx_cubic
Definition: index.F90:169
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
subroutine, public merge_sorted_arrays(array, sizes, merged, index_map)
This module contains subroutines, related to the initialization of the mesh.
Definition: mesh_init.F90:119
subroutine rebalance_array(grp, data_input, data_output, output_sizes)
re-distribute the points to improve load balancing
Definition: mesh_init.F90:659
subroutine, public mesh_init_stage_3(mesh, namespace, space, stencil, mc, parent, regenerate)
When running parallel in domains, stencil and np_stencil are needed to compute the ghost points....
Definition: mesh_init.F90:535
subroutine, public mesh_init_stage_1(mesh, namespace, space, box, coord_system, spacing, enlarge)
First stage mesh initialization.
Definition: mesh_init.F90:174
subroutine get_sizes_offsets(local_size, sizes, offsets, mpi_grp)
return the sizes and offsets of a distributed array for all tasks of a mpi group.
Definition: mesh_init.F90:1043
subroutine reorder_points(namespace, space, grp, idx, grid_to_spatial, grid_to_spatial_reordered)
reorder the points in the grid according to the variables MeshOrder and MeshLocalOrder
Definition: mesh_init.F90:765
subroutine, public mesh_init_stage_2(mesh, namespace, space, box, stencil, grp, regenerate)
This subroutine creates the global array of spatial indices and the inverse mapping.
Definition: mesh_init.F90:296
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
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(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_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
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, public mesh_partition_from_parent(mesh, parent)
create a mesh partition from a given parent mesh
subroutine, public mesh_partition_write_info(mesh, iunit, namespace)
subroutine, public mesh_partition_messages_debug(mesh, namespace)
subroutine, public mesh_partition(mesh, namespace, space, lapl_stencil, vsize)
This routine converts the mesh given by grid points into a graph.
subroutine, public mesh_partition_dump(restart, mesh, vsize, ierr)
subroutine, public mesh_partition_load(restart, mesh, ierr)
subroutine, public messages_end()
Definition: messages.F90:273
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
subroutine, public print_date(str)
Definition: messages.F90:983
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
This module contains some common usage patterns of MPI routines.
Definition: mpi_lib.F90:117
subroutine mpi_grp_init(grp, comm)
Initialize MPI group instance.
Definition: mpi.F90:407
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
Some general things and nomenclature:
Definition: par_vec.F90:173
subroutine, public par_vec_end(pv)
Deallocate memory used by pv.
Definition: par_vec.F90:752
subroutine, public par_vec_init(mpi_grp, np_global, idx, stencil, space, partition, pv, namespace)
Initializes a par_vec_type object (parallel vector).
Definition: par_vec.F90:302
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:623
subroutine, public partition_get_global(partition, part_global, root)
Returns the global partition. If root is present, the partition is gathered only in that node....
Definition: partition.F90:398
subroutine, public profiling_end(namespace)
Definition: profiling.F90:451
integer, parameter, public restart_partition
Definition: restart.F90:156
integer, parameter, public restart_type_dump
Definition: restart.F90:184
integer, parameter, public restart_type_load
Definition: restart.F90:184
This module is intended to contain "only mathematical" functions and procedures.
Definition: sort.F90:119
This module defines stencils used in Octopus.
Definition: stencil.F90:137
integer, dimension(7), parameter sizes
Definition: types.F90:152
type(type_t), parameter, public type_float
Definition: types.F90:136
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:120
subroutine, public make_array_larger(array, new_size)
Definition: utils.F90:680
class to tell whether a point is inside or outside
Definition: box.F90:143
Describes mesh distribution to nodes.
Definition: mesh.F90:188
This is defined even when running serial.
Definition: mpi.F90:144
Stores all communicators and groups.
Definition: multicomm.F90:208
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:165
int true(void)