38#include "../base/base_uses.f90"
44 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_fm_diag_utils'
48 INTEGER :: matrix_order = -1
49 INTEGER :: num_pe_old = -1
50 INTEGER :: num_pe_new = -1
51 INTEGER :: num_pe_opt = -1
52 INTEGER :: num_pe_max_nz_col = -1
53 LOGICAL :: redistribute = .false.
55 PROCEDURE, pass(self) :: write => cp_fm_redistribute_info_write
59 TYPE cp_fm_redistribute_type
61 INTEGER :: a = -1, x = -1
62 LOGICAL :: should_print = .false.
63 LOGICAL :: elpa_force_redistribute = .false.
65 INTEGER,
DIMENSION(:),
POINTER :: group_distribution => null(), &
66 group_partition => null()
69 END TYPE cp_fm_redistribute_type
72 TYPE(cp_fm_redistribute_type),
PRIVATE, &
73 SAVE :: work_redistribute
82#if defined(__parallel)
83 PUBLIC :: cp_fm_max_ncpu_non_zero_column
93 SUBROUTINE cp_fm_redistribute_info_write(self, io_unit)
95 INTEGER,
INTENT(IN) :: io_unit
97 WRITE (unit=io_unit, fmt=
"(A)")
""
98 WRITE (unit=io_unit, fmt=
"(T2,A,T71,I10)") &
99 "CP_FM_DIAG| Number of processes over which the matrix is distributed ", self%num_pe_old, &
100 "CP_FM_DIAG| Matrix order ", self%matrix_order
101 WRITE (unit=io_unit, fmt=
"(T2,A,T71,I10)") &
102 "CP_FM_DIAG| Optimal number of CPUs ", self%num_pe_opt
103 IF (self%num_pe_max_nz_col < 0)
THEN
104 WRITE (unit=io_unit, fmt=
"(T2,A,T71,A10)") &
105 "CP_FM_DIAG| Maximum number of CPUs (with non-zero columns) ",
"<N/A>"
107 WRITE (unit=io_unit, fmt=
"(T2,A,T71,I10)") &
108 "CP_FM_DIAG| Maximum number of CPUs (with non-zero columns): ", self%num_pe_max_nz_col
110 IF (self%redistribute)
THEN
111 WRITE (unit=io_unit, fmt=
"(T2,A,T71,I10)") &
112 "CP_FM_DIAG| Number of processes for the redistribution ", self%num_pe_new
114 WRITE (unit=io_unit, fmt=
"(T2,A)") &
115 "CP_FM_DIAG| The matrix will NOT be redistributed"
117 WRITE (unit=io_unit, fmt=
"(A)")
""
119 END SUBROUTINE cp_fm_redistribute_info_write
127 SUBROUTINE cp_fm_redistribute_work_finalize(has_redistributed)
128 LOGICAL,
INTENT(IN) :: has_redistributed
130 IF (
ASSOCIATED(work_redistribute%group_distribution))
THEN
131 IF (has_redistributed)
THEN
134 CALL work_redistribute%para_env_new%free()
135 DEALLOCATE (work_redistribute%para_env_new)
136 DEALLOCATE (work_redistribute%group_distribution)
137 DEALLOCATE (work_redistribute%group_partition)
141 NULLIFY (work_redistribute%group_distribution)
142 NULLIFY (work_redistribute%group_partition)
143 NULLIFY (work_redistribute%blacs_env_new)
144 NULLIFY (work_redistribute%para_env_new)
146 END SUBROUTINE cp_fm_redistribute_work_finalize
162 INTEGER,
INTENT(IN) :: a, x
163 LOGICAL,
INTENT(IN) :: should_print, elpa_force_redistribute
165 cpassert(a > 0 .AND. x > 0)
169 work_redistribute = cp_fm_redistribute_type()
170 work_redistribute%a = a
171 work_redistribute%x = x
172 work_redistribute%should_print = should_print
173 work_redistribute%elpa_force_redistribute = elpa_force_redistribute
183 PURE FUNCTION cp_fm_diag_get_optimal_ncpu(size)
RESULT(ncpu)
184 INTEGER,
INTENT(IN) :: size
187 ncpu = ((
size + work_redistribute%a*work_redistribute%x - 1)/ &
188 (work_redistribute%a*work_redistribute%x))*work_redistribute%a
190 END FUNCTION cp_fm_diag_get_optimal_ncpu
192#if defined(__parallel)
201 FUNCTION cp_fm_max_ncpu_non_zero_column(matrix_struct, ncpu_max, block_size)
RESULT(ncpu)
203 INTEGER,
INTENT(IN) :: ncpu_max, block_size
206 INTEGER :: gcd_max, ipe, jpe, npcol, nprow, nzero
207 INTEGER,
EXTERNAL :: numroc
209 ncpu = max(1, min(ncpu_max, matrix_struct%para_env%num_pe))
211 IF (ncpu > 2) ncpu = ncpu -
modulo(ncpu, 2)
214 IF (ncpu == matrix_struct%para_env%num_pe .AND. &
215 block_size == matrix_struct%nrow_block .AND. block_size == matrix_struct%ncol_block)
THEN
216 nzero = count(matrix_struct%nrow_locals == 0) + count(matrix_struct%ncol_locals == 0)
217 IF (nzero == 0)
RETURN
220 IF (ncpu > 2) ncpu = ncpu -
modulo(ncpu, 2)
229 DO ipe = 1, ceiling(sqrt(real(ncpu,
dp)))
231 IF (ipe*jpe /= ncpu)
THEN
234 IF (
gcd(ipe, jpe) >= gcd_max)
THEN
237 gcd_max =
gcd(ipe, jpe)
244 DO ipe = 0, npcol - 1
245 IF (numroc(matrix_struct%ncol_global, block_size, ipe, 0, npcol) == 0)
THEN
249 DO ipe = 0, nprow - 1
250 IF (numroc(matrix_struct%nrow_global, block_size, ipe, 0, nprow) == 0)
THEN
262 ncpu = ncpu -
modulo(ncpu, 2)
266 END FUNCTION cp_fm_max_ncpu_non_zero_column
285 caller_is_elpa, redist_info)
287 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
288 TYPE(
cp_fm_type),
INTENT(OUT) :: matrix_new, eigenvectors_new
289 LOGICAL,
OPTIONAL,
INTENT(IN) :: caller_is_elpa
291 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_redistribute_start'
297#if defined(__parallel)
298 REAL(kind=
dp) :: fake_local_data(1, 1)
299 INTEGER :: fake_descriptor(9), mepos_old, &
300 io_unit, ngroups, ncol_block, blksize, nrow_block
307 CALL timeset(routinen, handle)
309 IF (
PRESENT(caller_is_elpa))
THEN
311 is_elpa = caller_is_elpa
313 cpabort(
"CP2K compiled without the ELPA library.")
317#if defined(__parallel)
326 para_env => matrix%matrix_struct%para_env
327 mepos_old = para_env%mepos
332 rdinfo%matrix_order = matrix%matrix_struct%nrow_global
333 rdinfo%num_pe_old = para_env%num_pe
334 rdinfo%num_pe_opt = cp_fm_diag_get_optimal_ncpu(rdinfo%matrix_order)
335 rdinfo%num_pe_new = rdinfo%num_pe_opt
336 rdinfo%num_pe_max_nz_col = -1
337 rdinfo%redistribute = .false.
340 CALL cp_fm_get_info(matrix, ncol_block=ncol_block, nrow_block=nrow_block)
344 DO WHILE (2*blksize <= min(nrow_block, ncol_block))
351 rdinfo%num_pe_max_nz_col = cp_fm_max_ncpu_non_zero_column( &
352 matrix%matrix_struct, rdinfo%num_pe_old, blksize)
353 rdinfo%num_pe_new = rdinfo%num_pe_max_nz_col
354 IF (work_redistribute%elpa_force_redistribute .AND. rdinfo%num_pe_opt < rdinfo%num_pe_new)
THEN
355 rdinfo%num_pe_new = cp_fm_max_ncpu_non_zero_column( &
356 matrix%matrix_struct, rdinfo%num_pe_opt, blksize)
361 rdinfo%redistribute = (rdinfo%num_pe_old > rdinfo%num_pe_new) .OR. (blksize >= 0 .AND. &
362 ((blksize /= matrix%matrix_struct%ncol_block) .OR. (blksize /= matrix%matrix_struct%nrow_block)))
364 IF (work_redistribute%should_print .AND. io_unit > 0)
THEN
366 IF (work_redistribute%elpa_force_redistribute)
THEN
367 WRITE (unit=io_unit, fmt=
"(T2,A,T78,A3)") &
368 "CP_FM_DIAG| Force redistribute (ELPA):",
"YES"
370 WRITE (unit=io_unit, fmt=
"(T2,A,T79,A2)") &
371 "CP_FM_DIAG| Force redistribute (ELPA):",
"NO"
374 CALL rdinfo%write(io_unit)
379 IF (rdinfo%redistribute)
THEN
381 ALLOCATE (work_redistribute%group_distribution(0:rdinfo%num_pe_old - 1))
382 ALLOCATE (work_redistribute%group_partition(0:1))
383 work_redistribute%group_partition = [rdinfo%num_pe_new, rdinfo%num_pe_old - rdinfo%num_pe_new]
384 ALLOCATE (work_redistribute%para_env_new)
385 CALL work_redistribute%para_env_new%from_split( &
386 comm=para_env, ngroups=ngroups, group_distribution=work_redistribute%group_distribution, &
387 n_subgroups=2, group_partition=work_redistribute%group_partition)
389 IF (work_redistribute%group_distribution(mepos_old) == 0)
THEN
392 NULLIFY (work_redistribute%blacs_env_new)
393 CALL cp_blacs_env_create(blacs_env=work_redistribute%blacs_env_new, para_env=work_redistribute%para_env_new)
396 NULLIFY (fm_struct_new)
397 IF (nrow_block == -1 .OR. ncol_block == -1)
THEN
399 para_env=work_redistribute%para_env_new, &
400 context=work_redistribute%blacs_env_new, &
401 nrow_global=rdinfo%matrix_order, ncol_global=rdinfo%matrix_order, &
402 ncol_block=ncol_block, nrow_block=nrow_block)
405 para_env=work_redistribute%para_env_new, &
406 context=work_redistribute%blacs_env_new, &
407 nrow_global=rdinfo%matrix_order, ncol_global=rdinfo%matrix_order, &
408 ncol_block=ncol_block, nrow_block=nrow_block, force_block=.true.)
410 CALL cp_fm_create(matrix_new, matrix_struct=fm_struct_new, name=
"yevd_new_mat")
411 CALL cp_fm_create(eigenvectors_new, matrix_struct=fm_struct_new, name=
"yevd_new_vec")
415 CALL pdgemr2d(rdinfo%matrix_order, rdinfo%matrix_order, matrix%local_data(1, 1), 1, 1, &
416 matrix%matrix_struct%descriptor, &
417 matrix_new%local_data(1, 1), 1, 1, matrix_new%matrix_struct%descriptor, &
418 matrix%matrix_struct%context)
424 CALL pdgemr2d(rdinfo%matrix_order, rdinfo%matrix_order, matrix%local_data(1, 1), 1, 1, &
425 matrix%matrix_struct%descriptor, &
426 fake_local_data(1, 1), 1, 1, fake_descriptor, &
427 matrix%matrix_struct%context)
432 eigenvectors_new = eigenvectors
435 IF (
PRESENT(redist_info))
THEN
441 mark_used(eigenvectors)
442 mark_used(matrix_new)
443 mark_used(eigenvectors_new)
444 mark_used(redist_info)
445 cpabort(
"Routine called in non-parallel case.")
448 CALL timestop(handle)
467 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
468 REAL(kind=
dp),
DIMENSION(:),
INTENT(INOUT) :: eig
469 TYPE(
cp_fm_type),
INTENT(INOUT) :: matrix_new, eigenvectors_new
471 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_redistribute_end'
474#if defined(__parallel)
475 REAL(kind=
dp) :: fake_local_data(1, 1)
476 INTEGER :: fake_descriptor(9), mepos_old, n
480 CALL timeset(routinen, handle)
482#if defined(__parallel)
485 IF (
ASSOCIATED(work_redistribute%group_distribution))
THEN
486 n = matrix%matrix_struct%nrow_global
487 para_env => matrix%matrix_struct%para_env
488 mepos_old = para_env%mepos
490 IF (work_redistribute%group_distribution(mepos_old) == 0)
THEN
492 CALL pdgemr2d(n, n, eigenvectors_new%local_data(1, 1), 1, 1, eigenvectors_new%matrix_struct%descriptor, &
493 eigenvectors%local_data(1, 1), 1, 1, eigenvectors%matrix_struct%descriptor, &
494 eigenvectors%matrix_struct%context)
502 CALL pdgemr2d(n, n, fake_local_data(1, 1), 1, 1, fake_descriptor, &
503 eigenvectors%local_data(1, 1), 1, 1, eigenvectors%matrix_struct%descriptor, &
504 eigenvectors%matrix_struct%context)
507 CALL cp_fm_redistribute_work_finalize(work_redistribute%group_distribution(mepos_old) == 0)
510 CALL para_env%bcast(eig, 0)
516 mark_used(eigenvectors)
518 mark_used(matrix_new)
519 mark_used(eigenvectors_new)
520 cpabort(
"Routine called in non-parallel case.")
523 CALL timestop(handle)
542 caller_is_elpa, redist_info)
544 TYPE(
cp_cfm_type),
INTENT(IN) :: matrix, eigenvectors
545 TYPE(
cp_cfm_type),
INTENT(OUT) :: matrix_new, eigenvectors_new
546 LOGICAL,
OPTIONAL,
INTENT(IN) :: caller_is_elpa
548 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_cfm_redistribute_start'
554#if defined(__parallel)
555 COMPLEX(KIND=dp) :: fake_local_data(1, 1)
556 INTEGER :: fake_descriptor(9), mepos_old, &
557 io_unit, ngroups, ncol_block, blksize, nrow_block
564 CALL timeset(routinen, handle)
566 IF (
PRESENT(caller_is_elpa))
THEN
568 is_elpa = caller_is_elpa
570 cpabort(
"CP2K compiled without the ELPA library.")
574#if defined(__parallel)
583 para_env => matrix%matrix_struct%para_env
584 mepos_old = para_env%mepos
589 rdinfo%matrix_order = matrix%matrix_struct%nrow_global
590 rdinfo%num_pe_old = para_env%num_pe
591 rdinfo%num_pe_opt = cp_fm_diag_get_optimal_ncpu(rdinfo%matrix_order)
592 rdinfo%num_pe_new = rdinfo%num_pe_opt
593 rdinfo%num_pe_max_nz_col = -1
594 rdinfo%redistribute = .false.
597 CALL cp_cfm_get_info(matrix, ncol_block=ncol_block, nrow_block=nrow_block)
601 DO WHILE (2*blksize <= min(nrow_block, ncol_block))
608 rdinfo%num_pe_max_nz_col = cp_fm_max_ncpu_non_zero_column( &
609 matrix%matrix_struct, rdinfo%num_pe_old, blksize)
610 rdinfo%num_pe_new = rdinfo%num_pe_max_nz_col
611 IF (work_redistribute%elpa_force_redistribute .AND. rdinfo%num_pe_opt < rdinfo%num_pe_new)
THEN
612 rdinfo%num_pe_new = cp_fm_max_ncpu_non_zero_column( &
613 matrix%matrix_struct, rdinfo%num_pe_opt, blksize)
618 rdinfo%redistribute = (rdinfo%num_pe_old > rdinfo%num_pe_new) .OR. (blksize >= 0 .AND. &
619 ((blksize /= matrix%matrix_struct%ncol_block) .OR. (blksize /= matrix%matrix_struct%nrow_block)))
621 IF (work_redistribute%should_print .AND. io_unit > 0)
THEN
623 IF (work_redistribute%elpa_force_redistribute)
THEN
624 WRITE (unit=io_unit, fmt=
"(T2,A,T78,A3)") &
625 "CP_FM_DIAG| Force redistribute (ELPA):",
"YES"
627 WRITE (unit=io_unit, fmt=
"(T2,A,T79,A2)") &
628 "CP_FM_DIAG| Force redistribute (ELPA):",
"NO"
631 CALL rdinfo%write(io_unit)
636 IF (rdinfo%redistribute)
THEN
638 ALLOCATE (work_redistribute%group_distribution(0:rdinfo%num_pe_old - 1))
639 ALLOCATE (work_redistribute%group_partition(0:1))
640 work_redistribute%group_partition = [rdinfo%num_pe_new, rdinfo%num_pe_old - rdinfo%num_pe_new]
641 ALLOCATE (work_redistribute%para_env_new)
642 CALL work_redistribute%para_env_new%from_split( &
643 comm=para_env, ngroups=ngroups, group_distribution=work_redistribute%group_distribution, &
644 n_subgroups=2, group_partition=work_redistribute%group_partition)
646 IF (work_redistribute%group_distribution(mepos_old) == 0)
THEN
649 NULLIFY (work_redistribute%blacs_env_new)
650 CALL cp_blacs_env_create(blacs_env=work_redistribute%blacs_env_new, para_env=work_redistribute%para_env_new)
653 NULLIFY (fm_struct_new)
654 IF (nrow_block == -1 .OR. ncol_block == -1)
THEN
656 para_env=work_redistribute%para_env_new, &
657 context=work_redistribute%blacs_env_new, &
658 nrow_global=rdinfo%matrix_order, ncol_global=rdinfo%matrix_order, &
659 ncol_block=ncol_block, nrow_block=nrow_block)
662 para_env=work_redistribute%para_env_new, &
663 context=work_redistribute%blacs_env_new, &
664 nrow_global=rdinfo%matrix_order, ncol_global=rdinfo%matrix_order, &
665 ncol_block=ncol_block, nrow_block=nrow_block, force_block=.true.)
667 CALL cp_cfm_create(matrix_new, matrix_struct=fm_struct_new, name=
"zheevd_new_mat")
668 CALL cp_cfm_create(eigenvectors_new, matrix_struct=fm_struct_new, name=
"zheevd_new_vec")
672 CALL pzgemr2d(rdinfo%matrix_order, rdinfo%matrix_order, matrix%local_data(1, 1), 1, 1, &
673 matrix%matrix_struct%descriptor, &
674 matrix_new%local_data(1, 1), 1, 1, matrix_new%matrix_struct%descriptor, &
675 matrix%matrix_struct%context)
681 CALL pzgemr2d(rdinfo%matrix_order, rdinfo%matrix_order, matrix%local_data(1, 1), 1, 1, &
682 matrix%matrix_struct%descriptor, &
683 fake_local_data(1, 1), 1, 1, fake_descriptor, &
684 matrix%matrix_struct%context)
689 eigenvectors_new = eigenvectors
692 IF (
PRESENT(redist_info))
THEN
698 mark_used(eigenvectors)
699 mark_used(matrix_new)
700 mark_used(eigenvectors_new)
701 mark_used(redist_info)
702 cpabort(
"Routine called in non-parallel case.")
705 CALL timestop(handle)
723 TYPE(
cp_cfm_type),
INTENT(IN) :: matrix, eigenvectors
724 REAL(kind=
dp),
DIMENSION(:),
INTENT(INOUT) :: eig
725 TYPE(
cp_cfm_type),
INTENT(INOUT) :: matrix_new, eigenvectors_new
727 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_cfm_redistribute_end'
730#if defined(__parallel)
731 COMPLEX(KIND=dp) :: fake_local_data(1, 1)
732 INTEGER :: fake_descriptor(9), mepos_old, n
736 CALL timeset(routinen, handle)
738#if defined(__parallel)
741 IF (
ASSOCIATED(work_redistribute%group_distribution))
THEN
742 n = matrix%matrix_struct%nrow_global
743 para_env => matrix%matrix_struct%para_env
744 mepos_old = para_env%mepos
746 IF (work_redistribute%group_distribution(mepos_old) == 0)
THEN
748 CALL pzgemr2d(n, n, eigenvectors_new%local_data(1, 1), 1, 1, eigenvectors_new%matrix_struct%descriptor, &
749 eigenvectors%local_data(1, 1), 1, 1, eigenvectors%matrix_struct%descriptor, &
750 eigenvectors%matrix_struct%context)
758 CALL pzgemr2d(n, n, fake_local_data(1, 1), 1, 1, fake_descriptor, &
759 eigenvectors%local_data(1, 1), 1, 1, eigenvectors%matrix_struct%descriptor, &
760 eigenvectors%matrix_struct%context)
763 CALL cp_fm_redistribute_work_finalize(work_redistribute%group_distribution(mepos_old) == 0)
766 CALL para_env%bcast(eig, 0)
772 mark_used(eigenvectors)
774 mark_used(matrix_new)
775 mark_used(eigenvectors_new)
776 cpabort(
"Routine called in non-parallel case.")
779 CALL timestop(handle)
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
methods related to the blacs parallel environment
subroutine, public cp_blacs_env_release(blacs_env)
releases the given blacs_env
subroutine, public cp_blacs_env_create(blacs_env, para_env, blacs_grid_layout, blacs_repeatable, row_major, grid_2d)
allocates and initializes a type that represent a blacs context
Represents a complex full matrix distributed on many processors.
subroutine, public cp_cfm_release(matrix)
Releases a full matrix.
subroutine, public cp_cfm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
Creates a new full matrix with the given structure.
subroutine, public cp_cfm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, matrix_struct, para_env)
Returns information about a full matrix.
Auxiliary tools to redistribute cp_fm_type and cp_cfm_type matrices before and after diagonalization....
subroutine, public cp_fm_redistribute_end(matrix, eigenvectors, eig, matrix_new, eigenvectors_new)
Redistributes eigenvectors and eigenvalues back to the original communicator group.
subroutine, public cp_cfm_redistribute_start(matrix, eigenvectors, matrix_new, eigenvectors_new, caller_is_elpa, redist_info)
Determines the optimal number of CPUs for matrix diagonalization and redistributes the input matrices...
subroutine, public cp_cfm_redistribute_end(matrix, eigenvectors, eig, matrix_new, eigenvectors_new)
Redistributes eigenvectors and eigenvalues back to the original communicator group.
subroutine, public cp_fm_redistribute_start(matrix, eigenvectors, matrix_new, eigenvectors_new, caller_is_elpa, redist_info)
Determines the optimal number of CPUs for matrix diagonalization and redistributes the input matrices...
subroutine, public cp_fm_redistribute_init(a, x, should_print, elpa_force_redistribute)
Initializes the parameters that determine how to calculate the optimal number of CPUs for diagonalizi...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
Defines the basic variable types.
integer, parameter, public dp
Collection of simple mathematical functions and subroutines.
elemental integer function, public gcd(a, b)
computes the greatest common divisor of two number
Interface to the message passing library MPI.
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
Represent a complex full matrix.
keeps the information about the structure of a full matrix
type of a logger, at the moment it contains just a print level starting at which level it should be l...
stores all the informations relevant to an mpi environment