(git:f56c6e3)
Loading...
Searching...
No Matches
negf_matrix_utils.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Helper routines to manipulate with matrices.
10! **************************************************************************************************
12 USE cp_dbcsr_api, ONLY: &
15 dbcsr_type, dbcsr_type_no_symmetry
20 USE cp_fm_types, ONLY: cp_fm_get_info,&
24 USE kinds, ONLY: dp
25 USE kpoint_types, ONLY: get_kpoint_info,&
27 USE message_passing, ONLY: mp_comm_type,&
43#include "./base/base_uses.f90"
44
45 IMPLICIT NONE
46 PRIVATE
47
48 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_matrix_utils'
49 LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .true.
50
54
55CONTAINS
56
57! **************************************************************************************************
58!> \brief Compute the number of atomic orbitals of the given set of atoms.
59!> \param subsys QuickStep subsystem
60!> \param atom_list list of selected atom; when absent all the atoms are taken into account
61!> \return number of atomic orbitals
62!> \par History
63!> * 02.2017 created [Sergey Chulkov]
64! **************************************************************************************************
65 FUNCTION number_of_atomic_orbitals(subsys, atom_list) RESULT(nao)
66 TYPE(qs_subsys_type), POINTER :: subsys
67 INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: atom_list
68 INTEGER :: nao
69
70 INTEGER :: iatom, natoms
71 INTEGER, ALLOCATABLE, DIMENSION(:) :: nsgfs
72 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
73 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
74
75 CALL qs_subsys_get(subsys, particle_set=particle_set, qs_kind_set=qs_kind_set)
76 ALLOCATE (nsgfs(SIZE(particle_set)))
77 CALL get_particle_set(particle_set, qs_kind_set, nsgf=nsgfs)
78
79 IF (PRESENT(atom_list)) THEN
80 natoms = SIZE(atom_list)
81 nao = 0
82
83 DO iatom = 1, natoms
84 nao = nao + nsgfs(atom_list(iatom))
85 END DO
86 ELSE
87 nao = sum(nsgfs)
88 END IF
89
90 DEALLOCATE (nsgfs)
91 END FUNCTION number_of_atomic_orbitals
92
93! **************************************************************************************************
94!> \brief Populate relevant blocks of the DBCSR matrix using data from a ScaLAPACK matrix.
95!> Irrelevant blocks of the DBCSR matrix are kept untouched.
96!> \param fm dense matrix to copy
97!> \param matrix DBCSR matrix (modified on exit)
98!> \param atomlist_row set of atomic indices along the 1st (row) dimension
99!> \param atomlist_col set of atomic indices along the 2nd (column) dimension
100!> \param subsys subsystem environment
101!> \par History
102!> * 02.2017 created [Sergey Chulkov]
103! **************************************************************************************************
104 SUBROUTINE negf_copy_fm_submat_to_dbcsr(fm, matrix, atomlist_row, atomlist_col, subsys)
105 TYPE(cp_fm_type), INTENT(IN) :: fm
106 TYPE(dbcsr_type), POINTER :: matrix
107 INTEGER, DIMENSION(:), INTENT(in) :: atomlist_row, atomlist_col
108 TYPE(qs_subsys_type), POINTER :: subsys
109
110 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_copy_fm_submat_to_dbcsr'
111
112 INTEGER :: first_sgf_col, first_sgf_row, handle, iatom_col, iatom_row, icol, irow, &
113 natoms_col, natoms_row, ncols, nparticles, nrows
114 INTEGER, ALLOCATABLE, DIMENSION(:) :: nsgfs
115 LOGICAL :: found
116 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: fm_block
117 REAL(kind=dp), DIMENSION(:, :), POINTER :: sm_block
118 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
119 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
120
121 CALL timeset(routinen, handle)
122
123 cpassert(ASSOCIATED(matrix))
124 cpassert(ASSOCIATED(subsys))
125
126 CALL cp_fm_get_info(fm, nrow_global=nrows, ncol_global=ncols)
127
128 CALL qs_subsys_get(subsys, particle_set=particle_set, qs_kind_set=qs_kind_set)
129
130 natoms_row = SIZE(atomlist_row)
131 natoms_col = SIZE(atomlist_col)
132 nparticles = SIZE(particle_set)
133
134 ALLOCATE (nsgfs(nparticles))
135 CALL get_particle_set(particle_set, qs_kind_set, nsgf=nsgfs)
136
137 ALLOCATE (fm_block(nrows, ncols))
138 CALL cp_fm_get_submatrix(fm, fm_block)
139
140 first_sgf_col = 1
141 DO iatom_col = 1, natoms_col
142 first_sgf_row = 1
143 DO iatom_row = 1, natoms_row
144 CALL dbcsr_get_block_p(matrix=matrix, row=atomlist_row(iatom_row), col=atomlist_col(iatom_col), &
145 block=sm_block, found=found)
146 IF (found) THEN
147 ! the following LAPACK call violates the coding convention
148 !CALL dlacpy('F', nsgfs(atomlist_row(iatom_row)), nsgfs(atomlist_col(iatom_col)), &
149 ! fm_block(first_sgf_row, first_sgf_col), SIZE(fm_block, 1), sm_block(1, 1), SIZE(sm_block, 1))
150 nrows = nsgfs(atomlist_row(iatom_row))
151 ncols = nsgfs(atomlist_col(iatom_col))
152 DO icol = 1, ncols
153 DO irow = 1, nrows
154 sm_block(irow, icol) = fm_block(first_sgf_row + irow - 1, first_sgf_col + icol - 1)
155 END DO
156 END DO
157 END IF
158
159 first_sgf_row = first_sgf_row + nsgfs(atomlist_row(iatom_row))
160 END DO
161 first_sgf_col = first_sgf_col + nsgfs(atomlist_col(iatom_col))
162 END DO
163
164 DEALLOCATE (fm_block)
165 DEALLOCATE (nsgfs)
166
167 CALL timestop(handle)
168 END SUBROUTINE negf_copy_fm_submat_to_dbcsr
169
170! **************************************************************************************************
171!> \brief Extract part of the DBCSR matrix based on selected atoms and copy it into a dense matrix.
172!> \param matrix DBCSR matrix
173!> \param fm dense matrix (created and initialised on exit)
174!> \param atomlist_row set of atomic indices along the 1st (row) dimension
175!> \param atomlist_col set of atomic indices along the 2nd (column) dimension
176!> \param subsys subsystem environment
177!> \param mpi_comm_global MPI communicator which was used to distribute blocks of the DBCSR matrix.
178!> If missed, assume that both DBCSR and ScaLapack matrices are distributed
179!> across the same set of processors
180!> \param do_upper_diag initialise upper-triangular part of the dense matrix as well as diagonal elements
181!> \param do_lower initialise lower-triangular part of the dense matrix
182!> \par History
183!> * 02.2017 created [Sergey Chulkov]
184!> \note A naive implementation that copies relevant local DBCSR blocks into a 2-D matrix,
185!> performs collective summation, and then distributes the result. This approach seems to be
186!> optimal when processors are arranged into several independent MPI subgroups due to the fact
187!> that every subgroup automatically holds the copy of the dense matrix at the end, so
188!> we can avoid the final replication stage.
189! **************************************************************************************************
190 SUBROUTINE negf_copy_sym_dbcsr_to_fm_submat(matrix, fm, atomlist_row, atomlist_col, subsys, &
191 mpi_comm_global, do_upper_diag, do_lower)
192 TYPE(dbcsr_type), POINTER :: matrix
193 TYPE(cp_fm_type), INTENT(IN) :: fm
194 INTEGER, DIMENSION(:), INTENT(in) :: atomlist_row, atomlist_col
195 TYPE(qs_subsys_type), POINTER :: subsys
196
197 CLASS(mp_comm_type), INTENT(in) :: mpi_comm_global
198 LOGICAL, INTENT(in) :: do_upper_diag, do_lower
199
200 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_copy_sym_dbcsr_to_fm_submat'
201
202 INTEGER :: handle, iatom_col, iatom_row, icol, irow, natoms_col, natoms_row, ncols_fm, &
203 nparticles, nrows_fm, offset_sgf_col, offset_sgf_row
204 INTEGER, ALLOCATABLE, DIMENSION(:) :: nsgfs
205 LOGICAL :: found
206 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: r2d
207 REAL(kind=dp), DIMENSION(:, :), POINTER :: sm_block
208 TYPE(mp_para_env_type), POINTER :: para_env
209 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
210 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
211
212 CALL timeset(routinen, handle)
213
214 cpassert(ASSOCIATED(matrix))
215 cpassert(ASSOCIATED(subsys))
216
217 CALL qs_subsys_get(subsys, particle_set=particle_set, qs_kind_set=qs_kind_set)
218
219 natoms_row = SIZE(atomlist_row)
220 natoms_col = SIZE(atomlist_col)
221 nparticles = SIZE(particle_set)
222
223 ALLOCATE (nsgfs(nparticles))
224 CALL get_particle_set(particle_set, qs_kind_set, nsgf=nsgfs)
225
226 CALL cp_fm_get_info(fm, nrow_global=nrows_fm, ncol_global=ncols_fm, para_env=para_env)
227
228 IF (debug_this_module) THEN
229 cpassert(sum(nsgfs(atomlist_row(:))) == nrows_fm)
230 cpassert(sum(nsgfs(atomlist_col(:))) == ncols_fm)
231 END IF
232
233 ALLOCATE (r2d(nrows_fm, ncols_fm))
234 r2d(:, :) = 0.0_dp
235
236 offset_sgf_col = 0
237 DO iatom_col = 1, natoms_col
238 offset_sgf_row = 0
239
240 DO iatom_row = 1, natoms_row
241 IF (atomlist_row(iatom_row) <= atomlist_col(iatom_col)) THEN
242 IF (do_upper_diag) THEN
243 CALL dbcsr_get_block_p(matrix=matrix, row=atomlist_row(iatom_row), col=atomlist_col(iatom_col), &
244 block=sm_block, found=found)
245 END IF
246 ELSE
247 IF (do_lower) THEN
248 CALL dbcsr_get_block_p(matrix=matrix, row=atomlist_col(iatom_col), col=atomlist_row(iatom_row), &
249 block=sm_block, found=found)
250 END IF
251 END IF
252
253 IF (found) THEN
254 IF (atomlist_row(iatom_row) <= atomlist_col(iatom_col)) THEN
255 IF (do_upper_diag) THEN
256 DO icol = nsgfs(atomlist_col(iatom_col)), 1, -1
257 DO irow = nsgfs(atomlist_row(iatom_row)), 1, -1
258 r2d(offset_sgf_row + irow, offset_sgf_col + icol) = sm_block(irow, icol)
259 END DO
260 END DO
261 END IF
262 ELSE
263 IF (do_lower) THEN
264 DO icol = nsgfs(atomlist_col(iatom_col)), 1, -1
265 DO irow = nsgfs(atomlist_row(iatom_row)), 1, -1
266 r2d(offset_sgf_row + irow, offset_sgf_col + icol) = sm_block(icol, irow)
267 END DO
268 END DO
269 END IF
270 END IF
271 END IF
272
273 offset_sgf_row = offset_sgf_row + nsgfs(atomlist_row(iatom_row))
274 END DO
275 offset_sgf_col = offset_sgf_col + nsgfs(atomlist_col(iatom_col))
276 END DO
277
278 CALL mpi_comm_global%sum(r2d)
279
280 CALL cp_fm_set_submatrix(fm, r2d)
281
282 DEALLOCATE (r2d)
283 DEALLOCATE (nsgfs)
284
285 CALL timestop(handle)
287
288! **************************************************************************************************
289!> \brief Driver routine to extract diagonal and off-diagonal blocks from a symmetric DBCSR matrix.
290!> \param fm_cell0 extracted diagonal matrix block
291!> \param fm_cell1 extracted off-diagonal matrix block
292!> \param direction_axis axis towards the secondary unit cell
293!> \param matrix_kp set of DBCSR matrices
294!> \param atom_list0 list of atoms which belong to the primary contact unit cell
295!> \param atom_list1 list of atoms which belong to the secondary contact unit cell
296!> \param subsys QuickStep subsystem
297!> \param mpi_comm_global global MPI communicator
298!> \param kpoints ...
299!> \par History
300!> * 10.2017 created [Sergey Chulkov]
301!> * 10.2025 The subroutine is essentially modified. [Dmitry Ryndyk]
302! **************************************************************************************************
303 SUBROUTINE negf_copy_contact_matrix(fm_cell0, fm_cell1, direction_axis, matrix_kp, &
304 atom_list0, atom_list1, subsys, mpi_comm_global, kpoints)
305 TYPE(cp_fm_type), INTENT(IN) :: fm_cell0, fm_cell1
306 INTEGER, INTENT(in) :: direction_axis
307 TYPE(dbcsr_p_type), DIMENSION(:), INTENT(in), &
308 POINTER :: matrix_kp
309 INTEGER, DIMENSION(:), INTENT(in) :: atom_list0, atom_list1
310 TYPE(qs_subsys_type), POINTER :: subsys
311
312 CLASS(mp_comm_type), INTENT(in) :: mpi_comm_global
313 TYPE(kpoint_type), POINTER :: kpoints
314
315 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_copy_contact_matrix'
316
317 INTEGER :: direction_axis_abs, handle, rep, ncell, ic
318 TYPE(dbcsr_p_type), ALLOCATABLE, DIMENSION(:) :: matrix_cells_raw
319 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: mat_nosym
320 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: i_to_c
321 INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: c_to_i
322
323 CALL timeset(routinen, handle)
324
325 cpassert(ASSOCIATED(subsys))
326
327 direction_axis_abs = abs(direction_axis)
328
329 CALL desymmetrize_matrix(matrix_kp, mat_nosym, c_to_i, i_to_c, kpoints)
330 ncell = SIZE(i_to_c, 2) ! update the number of cells
331
332 ! 0 -- primary unit cell;
333 ! +- 1 -- upper- and lower-diagonal matrices for neighbor-cell matrix elements;
334 ! +- 2 -- for control
335 ALLOCATE (matrix_cells_raw(-2:2))
336 DO rep = -2, 2
337 NULLIFY (matrix_cells_raw(rep)%matrix)
338 CALL dbcsr_init_p(matrix_cells_raw(rep)%matrix)
339 CALL dbcsr_copy(matrix_cells_raw(rep)%matrix, mat_nosym(1)%matrix)
340 CALL dbcsr_set(matrix_cells_raw(rep)%matrix, 0.0_dp)
341 END DO
342
343 DO ic = 1, ncell
344 rep = i_to_c(direction_axis_abs, ic)
345 IF (abs(rep) <= 2) &
346 CALL dbcsr_add(matrix_cells_raw(rep)%matrix, mat_nosym(ic)%matrix, 1.0_dp, 1.0_dp)
347 END DO
348
349 IF (direction_axis >= 0) THEN
350
351 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(1)%matrix, fm_cell1, atom_list0, atom_list1, &
352 subsys, mpi_comm_global, do_upper_diag=.true., do_lower=.false.)
353 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(-1)%matrix, fm_cell0, atom_list0, atom_list1, &
354 subsys, mpi_comm_global, do_upper_diag=.false., do_lower=.true.)
355
356 ELSE
357
358 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(1)%matrix, fm_cell1, atom_list0, atom_list1, &
359 subsys, mpi_comm_global, do_upper_diag=.false., do_lower=.true.)
360 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(-1)%matrix, fm_cell0, atom_list0, atom_list1, &
361 subsys, mpi_comm_global, do_upper_diag=.true., do_lower=.false.)
362
363 END IF
364 CALL cp_fm_scale_and_add(1.0_dp, fm_cell1, 1.0_dp, fm_cell0)
365
366 ! symmetric matrix fm_cell0
367 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(0)%matrix, fm_cell0, atom_list0, atom_list0, &
368 subsys, mpi_comm_global, do_upper_diag=.true., do_lower=.true.)
369
370 ! clean up
371 DEALLOCATE (c_to_i, i_to_c)
372 DO ic = 1, ncell
373 CALL dbcsr_release(mat_nosym(ic)%matrix)
374 END DO
375 CALL dbcsr_deallocate_matrix_set(mat_nosym)
376 DO rep = -2, 2
377 CALL dbcsr_deallocate_matrix(matrix_cells_raw(rep)%matrix)
378 END DO
379 DEALLOCATE (matrix_cells_raw)
380
381 CALL timestop(handle)
382 END SUBROUTINE negf_copy_contact_matrix
383
384! **************************************************************************************************
385!> \brief Extract part of the DBCSR matrix based on selected atoms and copy it into another DBCSR
386!> matrix.
387!> \param matrix_contact extracted DBCSR matrix
388!> \param matrix_device original DBCSR matrix
389!> \param atom_list list of selected atoms
390!> \param atom_map atomic map between device and contact force environments
391!> \param para_env parallel environment
392! **************************************************************************************************
393 SUBROUTINE negf_reference_contact_matrix(matrix_contact, matrix_device, atom_list, atom_map, para_env)
394 TYPE(dbcsr_type), POINTER :: matrix_contact, matrix_device
395 INTEGER, DIMENSION(:), INTENT(in) :: atom_list
396 TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
397 TYPE(mp_para_env_type), POINTER :: para_env
398
399 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_reference_contact_matrix'
400
401 INTEGER :: handle, i1, i2, iatom_col, iatom_row, &
402 icol, iproc, irow, max_atom, &
403 mepos_plus1, n1, n2, natoms, offset
404 INTEGER, ALLOCATABLE, DIMENSION(:) :: recv_nelems, send_nelems
405 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: rank_contact, rank_device
406 LOGICAL :: found, transp
407 REAL(kind=dp), DIMENSION(:, :), POINTER :: rblock
408 TYPE(mp_request_type), ALLOCATABLE, DIMENSION(:) :: recv_handlers, send_handlers
409 TYPE(negf_allocatable_rvector), ALLOCATABLE, &
410 DIMENSION(:) :: recv_packed_blocks, send_packed_blocks
411
412 CALL timeset(routinen, handle)
413 mepos_plus1 = para_env%mepos + 1
414
415 natoms = SIZE(atom_list)
416 max_atom = 0
417 DO iatom_row = 1, natoms
418 IF (atom_map(iatom_row)%iatom > max_atom) max_atom = atom_map(iatom_row)%iatom
419 END DO
420
421 ! find out which block goes to which node
422 ALLOCATE (rank_contact(max_atom, max_atom))
423 ALLOCATE (rank_device(max_atom, max_atom))
424
425 rank_contact(:, :) = 0
426 rank_device(:, :) = 0
427
428 DO iatom_col = 1, natoms
429 DO iatom_row = 1, iatom_col
430 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
431 icol = atom_map(iatom_col)%iatom
432 irow = atom_map(iatom_row)%iatom
433 ELSE
434 icol = atom_map(iatom_row)%iatom
435 irow = atom_map(iatom_col)%iatom
436 END IF
437
438 CALL dbcsr_get_block_p(matrix=matrix_device, &
439 row=atom_list(iatom_row), col=atom_list(iatom_col), &
440 block=rblock, found=found)
441 IF (found) rank_device(irow, icol) = mepos_plus1
442
443 CALL dbcsr_get_block_p(matrix=matrix_contact, row=irow, col=icol, block=rblock, found=found)
444 IF (found) rank_contact(irow, icol) = mepos_plus1
445 END DO
446 END DO
447
448 CALL para_env%sum(rank_device)
449 CALL para_env%sum(rank_contact)
450
451 ! compute number of packed matrix elements to send to / receive from each processor
452 ALLOCATE (recv_nelems(para_env%num_pe))
453 ALLOCATE (send_nelems(para_env%num_pe))
454 recv_nelems(:) = 0
455 send_nelems(:) = 0
456
457 DO iatom_col = 1, natoms
458 DO iatom_row = 1, iatom_col
459 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
460 icol = atom_map(iatom_col)%iatom
461 irow = atom_map(iatom_row)%iatom
462 ELSE
463 icol = atom_map(iatom_row)%iatom
464 irow = atom_map(iatom_col)%iatom
465 END IF
466
467 CALL dbcsr_get_block_p(matrix=matrix_device, &
468 row=atom_list(iatom_row), col=atom_list(iatom_col), &
469 block=rblock, found=found)
470 IF (found) THEN
471 iproc = rank_contact(irow, icol)
472 IF (iproc > 0) &
473 send_nelems(iproc) = send_nelems(iproc) + SIZE(rblock)
474 END IF
475
476 CALL dbcsr_get_block_p(matrix=matrix_contact, row=irow, col=icol, block=rblock, found=found)
477 IF (found) THEN
478 iproc = rank_device(irow, icol)
479 IF (iproc > 0) &
480 recv_nelems(iproc) = recv_nelems(iproc) + SIZE(rblock)
481 END IF
482 END DO
483 END DO
484
485 ! pack blocks
486 ALLOCATE (recv_packed_blocks(para_env%num_pe))
487 DO iproc = 1, para_env%num_pe
488 IF (iproc /= mepos_plus1 .AND. recv_nelems(iproc) > 0) &
489 ALLOCATE (recv_packed_blocks(iproc)%vector(recv_nelems(iproc)))
490 END DO
491
492 ALLOCATE (send_packed_blocks(para_env%num_pe))
493 DO iproc = 1, para_env%num_pe
494 IF (send_nelems(iproc) > 0) &
495 ALLOCATE (send_packed_blocks(iproc)%vector(send_nelems(iproc)))
496 END DO
497
498 send_nelems(:) = 0
499 DO iatom_col = 1, natoms
500 DO iatom_row = 1, iatom_col
501 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
502 icol = atom_map(iatom_col)%iatom
503 irow = atom_map(iatom_row)%iatom
504 transp = .false.
505 ELSE
506 icol = atom_map(iatom_row)%iatom
507 irow = atom_map(iatom_col)%iatom
508 transp = .true.
509 END IF
510
511 iproc = rank_contact(irow, icol)
512 IF (iproc > 0) THEN
513 CALL dbcsr_get_block_p(matrix=matrix_device, &
514 row=atom_list(iatom_row), col=atom_list(iatom_col), &
515 block=rblock, found=found)
516 IF (found) THEN
517 offset = send_nelems(iproc)
518 n1 = SIZE(rblock, 1)
519 n2 = SIZE(rblock, 2)
520
521 IF (transp) THEN
522 DO i1 = 1, n1
523 DO i2 = 1, n2
524 send_packed_blocks(iproc)%vector(offset + i2) = rblock(i1, i2)
525 END DO
526 offset = offset + n2
527 END DO
528 ELSE
529 DO i2 = 1, n2
530 DO i1 = 1, n1
531 send_packed_blocks(iproc)%vector(offset + i1) = rblock(i1, i2)
532 END DO
533 offset = offset + n1
534 END DO
535 END IF
536
537 send_nelems(iproc) = offset
538 END IF
539 END IF
540 END DO
541 END DO
542
543 ! send blocks
544 ALLOCATE (recv_handlers(para_env%num_pe), send_handlers(para_env%num_pe))
545
546 DO iproc = 1, para_env%num_pe
547 IF (iproc /= mepos_plus1 .AND. send_nelems(iproc) > 0) THEN
548 CALL para_env%isend(send_packed_blocks(iproc)%vector, iproc - 1, send_handlers(iproc), 1)
549 END IF
550 END DO
551
552 ! receive blocks
553 DO iproc = 1, para_env%num_pe
554 IF (iproc /= mepos_plus1) THEN
555 IF (recv_nelems(iproc) > 0) THEN
556 CALL para_env%irecv(recv_packed_blocks(iproc)%vector, iproc - 1, recv_handlers(iproc), 1)
557 END IF
558 ELSE
559 IF (ALLOCATED(send_packed_blocks(iproc)%vector)) &
560 CALL move_alloc(send_packed_blocks(iproc)%vector, recv_packed_blocks(iproc)%vector)
561 END IF
562 END DO
563
564 ! unpack blocks
565 DO iproc = 1, para_env%num_pe
566 IF (iproc /= mepos_plus1 .AND. recv_nelems(iproc) > 0) &
567 CALL recv_handlers(iproc)%wait()
568 END DO
569
570 recv_nelems(:) = 0
571 DO iatom_col = 1, natoms
572 DO iatom_row = 1, iatom_col
573 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
574 icol = atom_map(iatom_col)%iatom
575 irow = atom_map(iatom_row)%iatom
576 ELSE
577 icol = atom_map(iatom_row)%iatom
578 irow = atom_map(iatom_col)%iatom
579 END IF
580
581 iproc = rank_device(irow, icol)
582 IF (iproc > 0) THEN
583 CALL dbcsr_get_block_p(matrix=matrix_contact, row=irow, col=icol, block=rblock, found=found)
584
585 IF (found) THEN
586 offset = recv_nelems(iproc)
587 n1 = SIZE(rblock, 1)
588 n2 = SIZE(rblock, 2)
589
590 DO i2 = 1, n2
591 DO i1 = 1, n1
592 rblock(i1, i2) = recv_packed_blocks(iproc)%vector(offset + i1)
593 END DO
594 offset = offset + n1
595 END DO
596
597 recv_nelems(iproc) = offset
598 END IF
599 END IF
600 END DO
601 END DO
602
603 DO iproc = 1, para_env%num_pe
604 IF (iproc /= mepos_plus1 .AND. send_nelems(iproc) > 0) &
605 CALL send_handlers(iproc)%wait()
606 END DO
607
608 ! release memory
609 DEALLOCATE (recv_handlers, send_handlers)
610
611 DO iproc = para_env%num_pe, 1, -1
612 IF (ALLOCATED(send_packed_blocks(iproc)%vector)) &
613 DEALLOCATE (send_packed_blocks(iproc)%vector)
614 END DO
615 DEALLOCATE (send_packed_blocks)
616
617 DO iproc = para_env%num_pe, 1, -1
618 IF (ALLOCATED(recv_packed_blocks(iproc)%vector)) &
619 DEALLOCATE (recv_packed_blocks(iproc)%vector)
620 END DO
621 DEALLOCATE (recv_packed_blocks)
622
623 DEALLOCATE (rank_contact, rank_device)
624 CALL timestop(handle)
625 END SUBROUTINE negf_reference_contact_matrix
626
627! **************************************************************************************************
628!> \brief Invert cell_to_index mapping between unit cells and DBCSR matrix images.
629!> \param cell_to_index mapping: unit_cell -> image_index
630!> \param nimages number of images
631!> \param index_to_cell inverted mapping: image_index -> unit_cell
632!> \par History
633!> * 10.2017 created [Sergey Chulkov]
634! **************************************************************************************************
635 SUBROUTINE invert_cell_to_index(cell_to_index, nimages, index_to_cell)
636 INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index
637 INTEGER, INTENT(in) :: nimages
638 INTEGER, DIMENSION(3, nimages), INTENT(out) :: index_to_cell
639
640 CHARACTER(LEN=*), PARAMETER :: routinen = 'invert_cell_to_index'
641
642 INTEGER :: handle, i1, i2, i3, image
643 INTEGER, DIMENSION(3) :: lbounds, ubounds
644
645 CALL timeset(routinen, handle)
646
647 index_to_cell(:, :) = 0
648 lbounds = lbound(cell_to_index)
649 ubounds = ubound(cell_to_index)
650
651 DO i3 = lbounds(3), ubounds(3) ! z
652 DO i2 = lbounds(2), ubounds(2) ! y
653 DO i1 = lbounds(1), ubounds(1) ! x
654 image = cell_to_index(i1, i2, i3)
655 IF (image > 0 .AND. image <= nimages) THEN
656 index_to_cell(1, image) = i1
657 index_to_cell(2, image) = i2
658 index_to_cell(3, image) = i3
659 END IF
660 END DO
661 END DO
662 END DO
663
664 CALL timestop(handle)
665 END SUBROUTINE invert_cell_to_index
666
667! **************************************************************************************************
668!> \brief Helper routine to obtain index of a DBCSR matrix image by its unit cell replica.
669!> Can be used with any usin cell.
670!> \param cell indices of the unit cell
671!> \param cell_to_index mapping: unit_cell -> image_index
672!> \return DBCSR matrix images
673!> (0 means there are no non-zero matrix elements in the image)
674!> \par History
675!> * 10.2017 created [Sergey Chulkov]
676! **************************************************************************************************
677 PURE FUNCTION get_index_by_cell(cell, cell_to_index) RESULT(image)
678 INTEGER, DIMENSION(3), INTENT(in) :: cell
679 INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index
680 INTEGER :: image
681
682 IF (lbound(cell_to_index, 1) <= cell(1) .AND. ubound(cell_to_index, 1) >= cell(1) .AND. &
683 lbound(cell_to_index, 2) <= cell(2) .AND. ubound(cell_to_index, 2) >= cell(2) .AND. &
684 lbound(cell_to_index, 3) <= cell(3) .AND. ubound(cell_to_index, 3) >= cell(3)) THEN
685
686 image = cell_to_index(cell(1), cell(2), cell(3))
687 ELSE
688 image = 0
689 END IF
690 END FUNCTION get_index_by_cell
691
692! **************************************************************************************************
693!> \brief Desymmetrizes the KS or S matrices for one of spin components
694!> \param mat Hamiltonian or overlap matrices
695!> \param mat_nosym Desymmetrized Hamiltonian or overlap matrices
696!> \param cell_to_index Mapping of cell indices to linear RS indices
697!> \param index_to_cell Mapping of linear RS indices to cell indices
698!> \param kpoints Kpoint environment
699!> \par History
700!> * 05.2020 created [Fabian Ducry]
701!> * 11.2025 Modified for one spin component. [Dmitry Ryndyk]
702!> \author Fabian Ducry
703! **************************************************************************************************
704 SUBROUTINE desymmetrize_matrix(mat, mat_nosym, cell_to_index, index_to_cell, kpoints)
705 TYPE(dbcsr_p_type), DIMENSION(:), INTENT(IN), &
706 POINTER :: mat
707 TYPE(dbcsr_p_type), DIMENSION(:), INTENT(INOUT), &
708 POINTER :: mat_nosym
709 INTEGER, ALLOCATABLE, DIMENSION(:, :, :), &
710 INTENT(OUT) :: cell_to_index
711 INTEGER, ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: index_to_cell
712 TYPE(kpoint_type), INTENT(IN), POINTER :: kpoints
713
714 CHARACTER(len=*), PARAMETER :: routinen = 'desymmetrize_matrix'
715
716 INTEGER :: handle, iatom, ic, icn, icol, irow, &
717 jatom, ncell, nomirror, nx, ny, nz
718 INTEGER, DIMENSION(3) :: cell
719 INTEGER, DIMENSION(:, :), POINTER :: i2c
720 INTEGER, DIMENSION(:, :, :), POINTER :: c2i
721 LOGICAL :: found, lwtr
722 REAL(kind=dp), DIMENSION(:, :), POINTER :: block
724 DIMENSION(:), POINTER :: nl_iterator
725 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
726 POINTER :: sab_nl
727
728 CALL timeset(routinen, handle)
729
730 i2c => kpoints%index_to_cell
731 c2i => kpoints%cell_to_index
732
733 ncell = SIZE(i2c, 2)
734
735 nx = max(abs(lbound(c2i, 1)), abs(ubound(c2i, 1)))
736 ny = max(abs(lbound(c2i, 2)), abs(ubound(c2i, 3)))
737 nz = max(abs(lbound(c2i, 3)), abs(ubound(c2i, 3)))
738 ALLOCATE (cell_to_index(-nx:nx, -ny:ny, -nz:nz))
739 cell_to_index(lbound(c2i, 1):ubound(c2i, 1), &
740 lbound(c2i, 2):ubound(c2i, 2), &
741 lbound(c2i, 3):ubound(c2i, 3)) = c2i
742
743 ! identify cells with no mirror img
744 nomirror = 0
745 DO ic = 1, ncell
746 cell = i2c(:, ic)
747 IF (cell_to_index(-cell(1), -cell(2), -cell(3)) == 0) &
748 nomirror = nomirror + 1
749 END DO
750
751 ! create the mirror imgs
752 ALLOCATE (index_to_cell(3, ncell + nomirror))
753 index_to_cell(:, 1:ncell) = i2c
754
755 nomirror = 0 ! count the imgs without mirror
756 DO ic = 1, ncell
757 cell = index_to_cell(:, ic)
758 IF (cell_to_index(-cell(1), -cell(2), -cell(3)) == 0) THEN
759 nomirror = nomirror + 1
760 index_to_cell(:, ncell + nomirror) = -cell
761 cell_to_index(-cell(1), -cell(2), -cell(3)) = ncell + nomirror
762 END IF
763 END DO
764 ncell = ncell + nomirror
765
766 CALL get_kpoint_info(kpoints, sab_nl=sab_nl)
767 ! allocate the nonsymmetric matrices
768 NULLIFY (mat_nosym)
769 CALL dbcsr_allocate_matrix_set(mat_nosym, ncell)
770 DO ic = 1, ncell
771 ALLOCATE (mat_nosym(ic)%matrix)
772 CALL dbcsr_create(matrix=mat_nosym(ic)%matrix, &
773 template=mat(1)%matrix, &
774 matrix_type=dbcsr_type_no_symmetry)
775 CALL cp_dbcsr_alloc_block_from_nbl(mat_nosym(ic)%matrix, &
776 sab_nl, desymmetrize=.true.)
777 CALL dbcsr_set(mat_nosym(ic)%matrix, 0.0_dp)
778 END DO
779
780 ! desymmetrize the matrix for real space printing
781 CALL neighbor_list_iterator_create(nl_iterator, sab_nl)
782 DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
783 CALL get_iterator_info(nl_iterator, iatom=iatom, jatom=jatom, cell=cell)
784
785 ic = cell_to_index(cell(1), cell(2), cell(3))
786 icn = cell_to_index(-cell(1), -cell(2), -cell(3))
787 cpassert(icn > 0)
788
789 irow = iatom
790 icol = jatom
791 lwtr = .false.
792 ! always copy from the top
793 IF (iatom > jatom) THEN
794 irow = jatom
795 icol = iatom
796 lwtr = .true.
797 END IF
798
799 CALL dbcsr_get_block_p(matrix=mat(ic)%matrix, &
800 row=irow, col=icol, block=block, found=found)
801 cpassert(found)
802
803 ! copy to M(R) at (iatom,jatom)
804 ! copy to M(-R) at (jatom,iatom)
805 IF (lwtr) THEN
806 CALL dbcsr_put_block(matrix=mat_nosym(ic)%matrix, &
807 row=iatom, col=jatom, block=transpose(block))
808 CALL dbcsr_put_block(matrix=mat_nosym(icn)%matrix, &
809 row=jatom, col=iatom, block=block)
810 ELSE
811 CALL dbcsr_put_block(matrix=mat_nosym(ic)%matrix, &
812 row=iatom, col=jatom, block=block)
813 CALL dbcsr_put_block(matrix=mat_nosym(icn)%matrix, &
814 row=jatom, col=iatom, block=transpose(block))
815 END IF
816 END DO
817 CALL neighbor_list_iterator_release(nl_iterator)
818
819 DO ic = 1, ncell
820 CALL dbcsr_finalize(mat_nosym(ic)%matrix)
821 END DO
822
823 CALL timestop(handle)
824
825 END SUBROUTINE desymmetrize_matrix
826
827END MODULE negf_matrix_utils
subroutine, public dbcsr_deallocate_matrix(matrix)
...
subroutine, public dbcsr_copy(matrix_b, matrix_a, name, keep_sparsity, keep_imaginary)
...
subroutine, public dbcsr_get_block_p(matrix, row, col, block, found, row_size, col_size)
...
subroutine, public dbcsr_init_p(matrix)
...
subroutine, public dbcsr_finalize(matrix)
...
subroutine, public dbcsr_set(matrix, alpha)
...
subroutine, public dbcsr_release(matrix)
...
subroutine, public dbcsr_put_block(matrix, row, col, block, summation)
...
subroutine, public dbcsr_add(matrix_a, matrix_b, alpha_scalar, beta_scalar)
...
DBCSR operations in CP2K.
Basic linear algebra operations for full matrices.
subroutine, public cp_fm_scale_and_add(alpha, matrix_a, beta, matrix_b)
calc A <- alpha*A + beta*B optimized for alpha == 1.0 (just add beta*B) and beta == 0....
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
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_set_submatrix(fm, new_values, start_row, start_col, n_rows, n_cols, alpha, beta, transpose)
sets a submatrix of a full matrix fm(start_row:start_row+n_rows,start_col:start_col+n_cols) = alpha*o...
subroutine, public cp_fm_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
gets a submatrix of a full matrix op(target_m)(1:n_rows,1:n_cols) =fm(start_row:start_row+n_rows,...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Types and basic routines needed for a kpoint calculation.
subroutine, public get_kpoint_info(kpoint, kp_scheme, nkp_grid, kp_shift, symmetry, verbose, full_grid, use_real_wfn, eps_geo, parallel_group_size, kp_range, nkp, xkp, wkp, para_env, blacs_env_all, para_env_kp, para_env_inter_kp, blacs_env, kp_env, kp_aux_env, mpools, iogrp, nkp_groups, kp_dist, cell_to_index, index_to_cell, sab_nl, sab_nl_nosym)
Retrieve information from a kpoint environment.
Interface to the message passing library MPI.
Allocatable vectors for NEGF based quantum transport calculations.
Map atoms between various force environments.
Helper routines to manipulate with matrices.
subroutine, public negf_reference_contact_matrix(matrix_contact, matrix_device, atom_list, atom_map, para_env)
Extract part of the DBCSR matrix based on selected atoms and copy it into another DBCSR matrix.
integer function, public number_of_atomic_orbitals(subsys, atom_list)
Compute the number of atomic orbitals of the given set of atoms.
pure integer function, public get_index_by_cell(cell, cell_to_index)
Helper routine to obtain index of a DBCSR matrix image by its unit cell replica. Can be used with any...
subroutine, public invert_cell_to_index(cell_to_index, nimages, index_to_cell)
Invert cell_to_index mapping between unit cells and DBCSR matrix images.
subroutine, public negf_copy_fm_submat_to_dbcsr(fm, matrix, atomlist_row, atomlist_col, subsys)
Populate relevant blocks of the DBCSR matrix using data from a ScaLAPACK matrix. Irrelevant blocks of...
subroutine, public negf_copy_contact_matrix(fm_cell0, fm_cell1, direction_axis, matrix_kp, atom_list0, atom_list1, subsys, mpi_comm_global, kpoints)
Driver routine to extract diagonal and off-diagonal blocks from a symmetric DBCSR matrix.
subroutine, public negf_copy_sym_dbcsr_to_fm_submat(matrix, fm, atomlist_row, atomlist_col, subsys, mpi_comm_global, do_upper_diag, do_lower)
Extract part of the DBCSR matrix based on selected atoms and copy it into a dense matrix.
Define methods related to particle_type.
subroutine, public get_particle_set(particle_set, qs_kind_set, first_sgf, last_sgf, nsgf, nmao, basis)
Get the components of a particle set.
Define the data structure for the particle information.
Define the quickstep kind type and their sub types.
Define the neighbor list data types and the corresponding functionality.
subroutine, public neighbor_list_iterator_create(iterator_set, nl, search, nthread)
Neighbor list iterator functions.
subroutine, public neighbor_list_iterator_release(iterator_set)
...
integer function, public neighbor_list_iterate(iterator_set, mepos)
...
subroutine, public get_iterator_info(iterator_set, mepos, ikind, jkind, nkind, ilist, nlist, inode, nnode, iatom, jatom, r, cell)
...
types that represent a quickstep subsys
subroutine, public qs_subsys_get(subsys, atomic_kinds, atomic_kind_set, particles, particle_set, local_particles, molecules, molecule_set, molecule_kinds, molecule_kind_set, local_molecules, para_env, colvar_p, shell_particles, core_particles, gci, multipoles, natom, nparticle, ncore, nshell, nkind, atprop, virial, results, cell, cell_ref, use_ref_cell, energy, force, qs_kind_set, cp_subsys, nelectron_total, nelectron_spin)
...
represent a full matrix
Contains information about kpoints.
stores all the informations relevant to an mpi environment
Structure that maps the given atom in the sourse FORCE_EVAL section with another atom from the target...
Provides all information about a quickstep kind.