1!--------------------------------------------------------------------------------------------------! 2! CP2K: A general program to perform molecular dynamics simulations ! 3! Copyright (C) 2000 - 2020 CP2K developers group ! 4!--------------------------------------------------------------------------------------------------! 5 6! ************************************************************************************************** 7!> \brief DBCSR output in CP2K 8!> \author VW 9!> \date 2009-09-09 10!> \version 0.1 11!> 12!> <b>Modification history:</b> 13!> - Created 2009-09-09 14! ************************************************************************************************** 15MODULE cp_dbcsr_output 16 USE atomic_kind_types, ONLY: atomic_kind_type,& 17 get_atomic_kind 18 USE basis_set_types, ONLY: get_gto_basis_set,& 19 gto_basis_set_type 20 USE cp_fm_types, ONLY: cp_fm_get_info,& 21 cp_fm_get_submatrix,& 22 cp_fm_type 23 USE cp_log_handling, ONLY: cp_get_default_logger,& 24 cp_logger_type 25 USE cp_para_types, ONLY: cp_para_env_type 26 USE dbcsr_api, ONLY: & 27 dbcsr_get_data_size, dbcsr_get_info, dbcsr_get_matrix_type, dbcsr_get_num_blocks, & 28 dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, dbcsr_iterator_start, & 29 dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_type, dbcsr_type_antisymmetric, & 30 dbcsr_type_no_symmetry, dbcsr_type_symmetric 31 USE kinds, ONLY: default_string_length,& 32 dp,& 33 int_8 34 USE machine, ONLY: m_flush 35 USE mathlib, ONLY: symmetrize_matrix 36 USE message_passing, ONLY: mp_max,& 37 mp_sum,& 38 mp_sync 39 USE orbital_pointers, ONLY: nso 40 USE particle_methods, ONLY: get_particle_set 41 USE particle_types, ONLY: particle_type 42 USE qs_environment_types, ONLY: get_qs_env,& 43 qs_environment_type 44 USE qs_kind_types, ONLY: get_qs_kind,& 45 get_qs_kind_set,& 46 qs_kind_type 47#include "./base/base_uses.f90" 48 49 IMPLICIT NONE 50 51 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_dbcsr_output' 52 53 PUBLIC :: cp_dbcsr_write_sparse_matrix 54 PUBLIC :: cp_dbcsr_write_matrix_dist 55 PUBLIC :: write_fm_with_basis_info 56 57 PRIVATE 58 59CONTAINS 60 61! ************************************************************************************************** 62!> \brief Print a spherical matrix of blacs type. 63!> \param blacs_matrix ... 64!> \param before ... 65!> \param after ... 66!> \param qs_env ... 67!> \param para_env ... 68!> \param first_row ... 69!> \param last_row ... 70!> \param first_col ... 71!> \param last_col ... 72!> \param output_unit ... 73!> \param omit_headers Write only the matrix data, not the row/column headers 74!> \author Creation (12.06.2001,MK) 75!> Allow for printing of a sub-matrix (01.07.2003,MK) 76! ************************************************************************************************** 77 SUBROUTINE write_fm_with_basis_info(blacs_matrix, before, after, qs_env, para_env, & 78 first_row, last_row, first_col, last_col, output_unit, omit_headers) 79 80 TYPE(cp_fm_type), POINTER :: blacs_matrix 81 INTEGER, INTENT(IN) :: before, after 82 TYPE(qs_environment_type), POINTER :: qs_env 83 TYPE(cp_para_env_type), POINTER :: para_env 84 INTEGER, INTENT(IN), OPTIONAL :: first_row, last_row, first_col, last_col 85 INTEGER, INTENT(IN) :: output_unit 86 LOGICAL, INTENT(IN), OPTIONAL :: omit_headers 87 88 CHARACTER(LEN=*), PARAMETER :: routineN = 'write_fm_with_basis_info', & 89 routineP = moduleN//':'//routineN 90 91 CHARACTER(LEN=60) :: matrix_name 92 INTEGER :: col1, col2, group, ncol_global, & 93 nrow_global, nsgf, row1, row2 94 LOGICAL :: my_omit_headers 95 REAL(KIND=dp), DIMENSION(:, :), POINTER :: matrix 96 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set 97 98 group = para_env%group 99 IF (.NOT. ASSOCIATED(blacs_matrix)) RETURN 100 CALL cp_fm_get_info(blacs_matrix, name=matrix_name, nrow_global=nrow_global, & 101 ncol_global=ncol_global) 102 103 ALLOCATE (matrix(nrow_global, ncol_global)) 104 CALL cp_fm_get_submatrix(blacs_matrix, matrix) 105 106 ! *** Get the matrix dimension and check the optional arguments *** 107 CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set) 108 CALL get_qs_kind_set(qs_kind_set=qs_kind_set, nsgf=nsgf) 109 110 IF (PRESENT(first_row)) THEN 111 row1 = MAX(1, first_row) 112 ELSE 113 row1 = 1 114 END IF 115 116 IF (PRESENT(last_row)) THEN 117 row2 = MIN(nsgf, last_row) 118 ELSE 119 row2 = nsgf 120 END IF 121 122 IF (PRESENT(first_col)) THEN 123 col1 = MAX(1, first_col) 124 ELSE 125 col1 = 1 126 END IF 127 128 IF (PRESENT(last_col)) THEN 129 col2 = MIN(nsgf, last_col) 130 ELSE 131 col2 = nsgf 132 END IF 133 134 IF (PRESENT(omit_headers)) THEN 135 my_omit_headers = omit_headers 136 ELSE 137 my_omit_headers = .FALSE. 138 END IF 139 140 CALL write_matrix_sym(matrix, matrix_name, before, after, qs_env, para_env, & 141 row1, row2, col1, col2, output_unit, omit_headers=my_omit_headers) 142 143 ! *** Release work storage *** 144 IF (ASSOCIATED(matrix)) THEN 145 DEALLOCATE (matrix) 146 END IF 147 148 END SUBROUTINE write_fm_with_basis_info 149 150! ************************************************************************************************** 151!> \brief ... 152!> \param sparse_matrix ... 153!> \param before ... 154!> \param after ... 155!> \param qs_env ... 156!> \param para_env ... 157!> \param first_row ... 158!> \param last_row ... 159!> \param first_col ... 160!> \param last_col ... 161!> \param scale ... 162!> \param output_unit ... 163!> \param omit_headers Write only the matrix data, not the row/column headers 164! ************************************************************************************************** 165 SUBROUTINE cp_dbcsr_write_sparse_matrix(sparse_matrix, before, after, qs_env, para_env, & 166 first_row, last_row, first_col, last_col, scale, & 167 output_unit, omit_headers) 168 169 TYPE(dbcsr_type) :: sparse_matrix 170 INTEGER, INTENT(IN) :: before, after 171 TYPE(qs_environment_type), POINTER :: qs_env 172 TYPE(cp_para_env_type), POINTER :: para_env 173 INTEGER, INTENT(IN), OPTIONAL :: first_row, last_row, first_col, last_col 174 REAL(dp), INTENT(IN), OPTIONAL :: scale 175 INTEGER, INTENT(IN) :: output_unit 176 LOGICAL, INTENT(IN), OPTIONAL :: omit_headers 177 178 CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_dbcsr_write_sparse_matrix', & 179 routineP = moduleN//':'//routineN 180 181 CHARACTER(LEN=default_string_length) :: matrix_name 182 INTEGER :: col1, col2, dim_col, dim_row, group, & 183 row1, row2 184 LOGICAL :: my_omit_headers, print_sym 185 REAL(KIND=dp), DIMENSION(:, :), POINTER :: matrix 186 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set 187 188 group = para_env%group 189 190 NULLIFY (matrix) 191 192 CALL copy_repl_dbcsr_to_repl_fm(sparse_matrix, matrix) 193 194 CALL mp_sum(matrix, group) 195 196 SELECT CASE (dbcsr_get_matrix_type(sparse_matrix)) 197 CASE (dbcsr_type_symmetric) 198 CALL symmetrize_matrix(matrix, "upper_to_lower") 199 print_sym = .TRUE. 200 CASE (dbcsr_type_antisymmetric) 201 CALL symmetrize_matrix(matrix, "anti_upper_to_lower") 202 print_sym = .TRUE. 203 CASE (dbcsr_type_no_symmetry) 204 print_sym = .FALSE. 205 CASE DEFAULT 206 CPABORT("WRONG") 207 END SELECT 208 209 ! *** Get the matrix dimension and check the optional arguments *** 210 CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set) 211 dim_row = SIZE(matrix, 1) 212 dim_col = SIZE(matrix, 2) 213 214 IF (PRESENT(first_row)) THEN 215 row1 = MAX(1, first_row) 216 ELSE 217 row1 = 1 218 END IF 219 220 IF (PRESENT(last_row)) THEN 221 row2 = MIN(dim_row, last_row) 222 ELSE 223 row2 = dim_row 224 END IF 225 226 IF (PRESENT(first_col)) THEN 227 col1 = MAX(1, first_col) 228 ELSE 229 col1 = 1 230 END IF 231 232 IF (PRESENT(last_col)) THEN 233 col2 = MIN(dim_col, last_col) 234 ELSE 235 col2 = dim_col 236 END IF 237 238 IF (PRESENT(scale)) THEN 239 matrix = matrix*scale 240 END IF 241 242 IF (PRESENT(omit_headers)) THEN 243 my_omit_headers = omit_headers 244 ELSE 245 my_omit_headers = .FALSE. 246 END IF 247 248 CALL dbcsr_get_info(sparse_matrix, name=matrix_name) 249 IF (print_sym) THEN 250 CALL write_matrix_sym(matrix, matrix_name, before, after, qs_env, para_env, & 251 row1, row2, col1, col2, output_unit, my_omit_headers) 252 ELSE 253 CALL write_matrix_gen(matrix, matrix_name, before, after, para_env, & 254 row1, row2, col1, col2, output_unit, my_omit_headers) 255 END IF 256 257 IF (ASSOCIATED(matrix)) THEN 258 DEALLOCATE (matrix) 259 END IF 260 261 END SUBROUTINE cp_dbcsr_write_sparse_matrix 262 263! ************************************************************************************************** 264!> \brief ... 265!> \param sparse_matrix ... 266!> \param fm ... 267! ************************************************************************************************** 268 SUBROUTINE copy_repl_dbcsr_to_repl_fm(sparse_matrix, fm) 269 270 TYPE(dbcsr_type) :: sparse_matrix 271 REAL(KIND=dp), DIMENSION(:, :), POINTER :: fm 272 273 CHARACTER(len=*), PARAMETER :: routineN = 'copy_repl_dbcsr_to_repl_fm', & 274 routineP = moduleN//':'//routineN 275 276 INTEGER :: blk, col, handle, i, j, nblkcols_total, & 277 nblkrows_total, nc, nr, row 278 INTEGER, ALLOCATABLE, DIMENSION(:) :: c_offset, r_offset 279 INTEGER, DIMENSION(:), POINTER :: col_blk_size, row_blk_size 280 REAL(KIND=dp), DIMENSION(:, :), POINTER :: DATA 281 TYPE(dbcsr_iterator_type) :: iter 282 283 CALL timeset(routineN, handle) 284 285 IF (ASSOCIATED(fm)) DEALLOCATE (fm) 286 287 CALL dbcsr_get_info(matrix=sparse_matrix, & 288 col_blk_size=col_blk_size, & 289 row_blk_size=row_blk_size, & 290 nblkrows_total=nblkrows_total, & 291 nblkcols_total=nblkcols_total) 292 293 !> this should be precomputed somewhere else 294 ALLOCATE (r_offset(nblkrows_total), c_offset(nblkcols_total)) 295 296 r_offset(1) = 1 297 DO row = 2, nblkrows_total 298 r_offset(row) = r_offset(row - 1) + row_blk_size(row - 1) 299 ENDDO 300 nr = SUM(row_blk_size) 301 c_offset(1) = 1 302 DO col = 2, nblkcols_total 303 c_offset(col) = c_offset(col - 1) + col_blk_size(col - 1) 304 ENDDO 305 nc = SUM(col_blk_size) 306 !< 307 308 ALLOCATE (fm(nr, nc)) 309 310 fm(:, :) = 0.0_dp 311 312 CALL dbcsr_iterator_start(iter, sparse_matrix) 313 DO WHILE (dbcsr_iterator_blocks_left(iter)) 314 CALL dbcsr_iterator_next_block(iter, row, col, DATA, blk) 315 DO j = 1, SIZE(DATA, 2) 316 DO i = 1, SIZE(DATA, 1) 317 fm(r_offset(row) + i - 1, c_offset(col) + j - 1) = DATA(i, j) 318 ENDDO 319 ENDDO 320 ENDDO 321 CALL dbcsr_iterator_stop(iter) 322 323 DEALLOCATE (r_offset, c_offset) 324 325 CALL timestop(handle) 326 327 END SUBROUTINE copy_repl_dbcsr_to_repl_fm 328 329! ************************************************************************************************** 330!> \brief Write a matrix or a sub-matrix to the output unit (symmetric) 331!> \param matrix ... 332!> \param matrix_name ... 333!> \param before ... 334!> \param after ... 335!> \param qs_env ... 336!> \param para_env ... 337!> \param first_row ... 338!> \param last_row ... 339!> \param first_col ... 340!> \param last_col ... 341!> \param output_unit ... 342!> \param omit_headers Write only the matrix data, not the row/column headers 343!> \author Creation (01.07.2003,MK) 344! ************************************************************************************************** 345 SUBROUTINE write_matrix_sym(matrix, matrix_name, before, after, qs_env, para_env, & 346 first_row, last_row, first_col, last_col, output_unit, omit_headers) 347 348 REAL(KIND=dp), DIMENSION(:, :), POINTER :: matrix 349 CHARACTER(LEN=*), INTENT(IN) :: matrix_name 350 INTEGER, INTENT(IN) :: before, after 351 TYPE(qs_environment_type), POINTER :: qs_env 352 TYPE(cp_para_env_type), POINTER :: para_env 353 INTEGER, INTENT(IN) :: first_row, last_row, first_col, & 354 last_col, output_unit 355 LOGICAL, INTENT(IN) :: omit_headers 356 357 CHARACTER(LEN=*), PARAMETER :: routineN = 'write_matrix_sym', & 358 routineP = moduleN//':'//routineN 359 360 CHARACTER(LEN=2) :: element_symbol 361 CHARACTER(LEN=25) :: fmtstr1 362 CHARACTER(LEN=35) :: fmtstr2 363 CHARACTER(LEN=6), DIMENSION(:), POINTER :: sgf_symbol 364 INTEGER :: from, group, iatom, icol, ikind, irow, & 365 iset, isgf, ishell, iso, jcol, l, & 366 left, natom, ncol, ndigits, nset, & 367 nsgf, right, to, width 368 INTEGER, ALLOCATABLE, DIMENSION(:) :: first_sgf, last_sgf 369 INTEGER, DIMENSION(:), POINTER :: nshell 370 INTEGER, DIMENSION(:, :), POINTER :: lshell 371 TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set 372 TYPE(gto_basis_set_type), POINTER :: orb_basis_set 373 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set 374 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set 375 376 group = para_env%group 377 378 IF (output_unit > 0) THEN 379 CALL m_flush(output_unit) 380 381 CALL get_qs_env(qs_env=qs_env, & 382 qs_kind_set=qs_kind_set, & 383 atomic_kind_set=atomic_kind_set, & 384 particle_set=particle_set) 385 386 natom = SIZE(particle_set) 387 388 CALL get_qs_kind_set(qs_kind_set=qs_kind_set, nsgf=nsgf) 389 390 ALLOCATE (first_sgf(natom)) 391 ALLOCATE (last_sgf(natom)) 392 CALL get_particle_set(particle_set, qs_kind_set, & 393 first_sgf=first_sgf, & 394 last_sgf=last_sgf) 395 396 ! *** Definition of the variable formats *** 397 fmtstr1 = "(/,T2,23X, ( X,I5, X))" 398 IF (omit_headers) THEN 399 fmtstr2 = "(T2, (1X,F . ))" 400 ELSE 401 fmtstr2 = "(T2,2I5,2X,A2,1X,A8, (1X,F . ))" 402 ENDIF 403 404 ! *** Write headline *** 405 WRITE (UNIT=output_unit, FMT="(/,/,T2,A)") TRIM(matrix_name) 406 407 ! *** Write the variable format strings *** 408 ndigits = after 409 410 width = before + ndigits + 3 411 ncol = INT(56/width) 412 413 right = MAX((ndigits - 2), 1) 414 left = width - right - 5 415 416 WRITE (UNIT=fmtstr1(11:12), FMT="(I2)") ncol 417 WRITE (UNIT=fmtstr1(14:15), FMT="(I2)") left 418 WRITE (UNIT=fmtstr1(21:22), FMT="(I2)") right 419 420 IF (omit_headers) THEN 421 WRITE (UNIT=fmtstr2(6:7), FMT="(I2)") ncol 422 WRITE (UNIT=fmtstr2(13:14), FMT="(I2)") width - 1 423 WRITE (UNIT=fmtstr2(16:17), FMT="(I2)") ndigits 424 ELSE 425 WRITE (UNIT=fmtstr2(22:23), FMT="(I2)") ncol 426 WRITE (UNIT=fmtstr2(29:30), FMT="(I2)") width - 1 427 WRITE (UNIT=fmtstr2(32:33), FMT="(I2)") ndigits 428 END IF 429 430 ! *** Write the matrix in the selected format *** 431 DO icol = first_col, last_col, ncol 432 from = icol 433 to = MIN((from + ncol - 1), last_col) 434 IF (.NOT. omit_headers) THEN 435 WRITE (UNIT=output_unit, FMT=fmtstr1) (jcol, jcol=from, to) 436 ENDIF 437 irow = 1 438 DO iatom = 1, natom 439 NULLIFY (orb_basis_set) 440 CALL get_atomic_kind(particle_set(iatom)%atomic_kind, & 441 kind_number=ikind, element_symbol=element_symbol) 442 CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set) 443 IF (ASSOCIATED(orb_basis_set)) THEN 444 CALL get_gto_basis_set(gto_basis_set=orb_basis_set, & 445 nset=nset, nshell=nshell, l=lshell, sgf_symbol=sgf_symbol) 446 isgf = 1 447 DO iset = 1, nset 448 DO ishell = 1, nshell(iset) 449 l = lshell(ishell, iset) 450 DO iso = 1, nso(l) 451 IF ((irow >= first_row) .AND. (irow <= last_row)) THEN 452 IF (omit_headers) THEN 453 WRITE (UNIT=output_unit, FMT=fmtstr2) & 454 (matrix(irow, jcol), jcol=from, to) 455 ELSE 456 WRITE (UNIT=output_unit, FMT=fmtstr2) & 457 irow, iatom, element_symbol, sgf_symbol(isgf), & 458 (matrix(irow, jcol), jcol=from, to) 459 END IF 460 END IF 461 isgf = isgf + 1 462 irow = irow + 1 463 END DO 464 END DO 465 END DO 466 IF ((irow >= first_row) .AND. (irow <= last_row)) THEN 467 WRITE (UNIT=output_unit, FMT="(A)") 468 END IF 469 ELSE 470 DO iso = first_sgf(iatom), last_sgf(iatom) 471 IF ((irow >= first_row) .AND. (irow <= last_row)) THEN 472 IF (omit_headers) THEN 473 WRITE (UNIT=output_unit, FMT=fmtstr2) & 474 (matrix(irow, jcol), jcol=from, to) 475 ELSE 476 WRITE (UNIT=output_unit, FMT=fmtstr2) & 477 irow, iatom, element_symbol, " ", & 478 (matrix(irow, jcol), jcol=from, to) 479 END IF 480 END IF 481 irow = irow + 1 482 END DO 483 IF ((irow >= first_row) .AND. (irow <= last_row)) THEN 484 WRITE (UNIT=output_unit, FMT="(A)") 485 END IF 486 END IF 487 END DO 488 END DO 489 490 WRITE (UNIT=output_unit, FMT="(/)") 491 DEALLOCATE (first_sgf) 492 DEALLOCATE (last_sgf) 493 END IF 494 495 CALL mp_sync(group) 496 IF (output_unit > 0) CALL m_flush(output_unit) 497 498 END SUBROUTINE write_matrix_sym 499 500! ************************************************************************************************** 501!> \brief Write a matrix not necessarily symmetric (no index with atomic labels) 502!> \param matrix ... 503!> \param matrix_name ... 504!> \param before ... 505!> \param after ... 506!> \param para_env ... 507!> \param first_row ... 508!> \param last_row ... 509!> \param first_col ... 510!> \param last_col ... 511!> \param output_unit ... 512!> \param omit_headers Write only the matrix data, not the row/column headers 513!> \author Teodoro Laino [tlaino] - 10.2007 - University of Zurich 514! ************************************************************************************************** 515 SUBROUTINE write_matrix_gen(matrix, matrix_name, before, after, para_env, & 516 first_row, last_row, first_col, last_col, output_unit, omit_headers) 517 518 REAL(KIND=dp), DIMENSION(:, :), POINTER :: matrix 519 CHARACTER(LEN=*), INTENT(IN) :: matrix_name 520 INTEGER, INTENT(IN) :: before, after 521 TYPE(cp_para_env_type), POINTER :: para_env 522 INTEGER, INTENT(IN) :: first_row, last_row, first_col, & 523 last_col, output_unit 524 LOGICAL, INTENT(IN) :: omit_headers 525 526 CHARACTER(LEN=*), PARAMETER :: routineN = 'write_matrix_gen', & 527 routineP = moduleN//':'//routineN 528 529 CHARACTER(LEN=25) :: fmtstr1 530 CHARACTER(LEN=35) :: fmtstr2 531 INTEGER :: from, group, icol, irow, jcol, left, & 532 ncol, ndigits, right, to, width 533 534 group = para_env%group 535 536 IF (output_unit > 0) THEN 537 CALL m_flush(output_unit) 538 539 ! *** Definition of the variable formats *** 540 fmtstr1 = "(/,T2,23X, ( X,I5, X))" 541 IF (omit_headers) THEN 542 fmtstr2 = "(T2, (1X,F . ))" 543 ELSE 544 fmtstr2 = "(T2, I5, 18X, (1X,F . ))" 545 END IF 546 547 ! *** Write headline *** 548 WRITE (UNIT=output_unit, FMT="(/,/,T2,A)") TRIM(matrix_name) 549 550 ! *** Write the variable format strings *** 551 ndigits = after 552 553 width = before + ndigits + 3 554 ncol = INT(56/width) 555 556 right = MAX((ndigits - 2), 1) 557 left = width - right - 5 558 559 WRITE (UNIT=fmtstr1(11:12), FMT="(I2)") ncol 560 WRITE (UNIT=fmtstr1(14:15), FMT="(I2)") left 561 WRITE (UNIT=fmtstr1(21:22), FMT="(I2)") right 562 563 IF (omit_headers) THEN 564 WRITE (UNIT=fmtstr2(6:7), FMT="(I2)") ncol 565 WRITE (UNIT=fmtstr2(13:14), FMT="(I2)") width - 1 566 WRITE (UNIT=fmtstr2(16:17), FMT="(I2)") ndigits 567 ELSE 568 WRITE (UNIT=fmtstr2(22:23), FMT="(I2)") ncol 569 WRITE (UNIT=fmtstr2(29:30), FMT="(I2)") width - 1 570 WRITE (UNIT=fmtstr2(32:33), FMT="(I2)") ndigits 571 ENDIF 572 573 ! *** Write the matrix in the selected format *** 574 DO icol = first_col, last_col, ncol 575 from = icol 576 to = MIN((from + ncol - 1), last_col) 577 IF (.NOT. omit_headers) THEN 578 WRITE (UNIT=output_unit, FMT=fmtstr1) (jcol, jcol=from, to) 579 END IF 580 irow = 1 581 DO irow = first_row, last_row 582 IF (omit_headers) THEN 583 WRITE (UNIT=output_unit, FMT=fmtstr2) & 584 irow, (matrix(irow, jcol), jcol=from, to) 585 ELSE 586 WRITE (UNIT=output_unit, FMT=fmtstr2) & 587 (matrix(irow, jcol), jcol=from, to) 588 END IF 589 END DO 590 END DO 591 592 WRITE (UNIT=output_unit, FMT="(/)") 593 END IF 594 595 CALL mp_sync(group) 596 IF (output_unit > 0) CALL m_flush(output_unit) 597 598 END SUBROUTINE write_matrix_gen 599 600! ************************************************************************************************** 601!> \brief Print the distribution of a sparse matrix. 602!> \param matrix ... 603!> \param output_unit ... 604!> \param para_env ... 605!> \par History 606!> Creation (25.06.2003,MK) 607! ************************************************************************************************** 608 SUBROUTINE cp_dbcsr_write_matrix_dist(matrix, output_unit, para_env) 609 TYPE(dbcsr_type) :: matrix 610 INTEGER, INTENT(IN) :: output_unit 611 TYPE(cp_para_env_type), POINTER :: para_env 612 613 CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_dbcsr_write_matrix_dist', & 614 routineP = moduleN//':'//routineN 615 LOGICAL, PARAMETER :: full_output = .FALSE. 616 617 CHARACTER :: matrix_type 618 CHARACTER(LEN=default_string_length) :: matrix_name 619 INTEGER :: group, handle, ipe, mype, natom, & 620 nblock_max, nelement_max, npe, nrow, & 621 tmp(2) 622 INTEGER(KIND=int_8) :: nblock_sum, nblock_tot, nelement_sum 623 INTEGER, ALLOCATABLE, DIMENSION(:) :: nblock, nelement 624 LOGICAL :: ionode 625 REAL(KIND=dp) :: occupation 626 TYPE(cp_logger_type), POINTER :: logger 627 628 NULLIFY (logger) 629 logger => cp_get_default_logger() 630 631 CALL timeset(routineN, handle) 632 633 group = para_env%group 634 ionode = para_env%ionode 635 mype = para_env%mepos + 1 636 npe = para_env%num_pe 637 638 ! *** Allocate work storage *** 639 ALLOCATE (nblock(npe)) 640 nblock(:) = 0 641 642 ALLOCATE (nelement(npe)) 643 nelement(:) = 0 644 645 nblock(mype) = dbcsr_get_num_blocks(matrix) 646 nelement(mype) = dbcsr_get_data_size(matrix) 647 648 CALL dbcsr_get_info(matrix=matrix, & 649 name=matrix_name, & 650 matrix_type=matrix_type, & 651 nblkrows_total=natom, & 652 nfullrows_total=nrow) 653 654 IF (full_output) THEN 655 ! XXXXXXXX should gather/scatter this on ionode 656 CALL mp_sum(nblock, group) 657 CALL mp_sum(nelement, group) 658 659 nblock_sum = SUM(INT(nblock, KIND=int_8)) 660 nelement_sum = SUM(INT(nelement, KIND=int_8)) 661 ELSE 662 nblock_sum = nblock(mype) 663 nblock_max = nblock(mype) 664 nelement_sum = nelement(mype) 665 nelement_max = nelement(mype) 666 CALL mp_sum(nblock_sum, group) 667 CALL mp_sum(nelement_sum, group) 668 tmp = (/nblock_max, nelement_max/) 669 CALL mp_max(tmp, group) 670 nblock_max = tmp(1); nelement_max = tmp(2) 671 ENDIF 672 673 IF (matrix_type == dbcsr_type_symmetric .OR. & 674 matrix_type == dbcsr_type_antisymmetric) THEN 675 nblock_tot = INT(natom, KIND=int_8)*INT(natom + 1, KIND=int_8)/2 676 ELSE 677 nblock_tot = INT(natom, KIND=int_8)**2 678 END IF 679 680 occupation = -1.0_dp 681 IF (nblock_tot .NE. 0) occupation = 100.0_dp*REAL(nblock_sum, dp)/REAL(nblock_tot, dp) 682 683 IF (ionode) THEN 684 WRITE (UNIT=output_unit, FMT="(/,/,T2,A)") & 685 "DISTRIBUTION OF THE "//TRIM(matrix_name) 686 IF (full_output) THEN 687 WRITE (UNIT=output_unit, FMT="(/,T3,A,/,/,(I9,T27,I10,T55,I10))") & 688 "Process Number of matrix blocks Number of matrix elements", & 689 (ipe - 1, nblock(ipe), nelement(ipe), ipe=1, npe) 690 WRITE (UNIT=output_unit, FMT="(/,T7,A3,T27,I10,T55,I10)") & 691 "Sum", nblock_sum, nelement_sum 692 WRITE (UNIT=output_unit, FMT="(/,T7,A3,T27,I10,A,F5.1,A,T55,I10,A,F5.1,A)") & 693 " of", nblock_tot, " (", occupation, " % occupation)" 694 ELSE 695 WRITE (UNIT=output_unit, FMT="(T15,A,T68,I13)") "Number of non-zero blocks:", nblock_sum 696 WRITE (UNIT=output_unit, FMT="(T15,A,T75,F6.2)") "Percentage non-zero blocks:", occupation 697 WRITE (UNIT=output_unit, FMT="(T15,A,T68,I13)") "Average number of blocks per CPU:", & 698 (nblock_sum + npe - 1)/npe 699 WRITE (UNIT=output_unit, FMT="(T15,A,T68,I13)") "Maximum number of blocks per CPU:", nblock_max 700 WRITE (UNIT=output_unit, FMT="(T15,A,T68,I13)") "Average number of matrix elements per CPU:", & 701 (nelement_sum + npe - 1)/npe 702 WRITE (UNIT=output_unit, FMT="(T15,A,T68,I13)") "Maximum number of matrix elements per CPU:", & 703 nelement_max 704 ENDIF 705 END IF 706 707 ! *** Release work storage *** 708 DEALLOCATE (nblock) 709 710 DEALLOCATE (nelement) 711 712 CALL timestop(handle) 713 714 END SUBROUTINE cp_dbcsr_write_matrix_dist 715 716END MODULE cp_dbcsr_output 717