(git:fdbe441)
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-2026 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) THEN
346 CALL dbcsr_add(matrix_cells_raw(rep)%matrix, mat_nosym(ic)%matrix, 1.0_dp, 1.0_dp)
347 END IF
348 END DO
349
350 IF (direction_axis >= 0) THEN
351
352 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(1)%matrix, fm_cell1, atom_list0, atom_list1, &
353 subsys, mpi_comm_global, do_upper_diag=.true., do_lower=.false.)
354 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(-1)%matrix, fm_cell0, atom_list0, atom_list1, &
355 subsys, mpi_comm_global, do_upper_diag=.false., do_lower=.true.)
356
357 ELSE
358
359 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(1)%matrix, fm_cell1, atom_list0, atom_list1, &
360 subsys, mpi_comm_global, do_upper_diag=.false., do_lower=.true.)
361 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(-1)%matrix, fm_cell0, atom_list0, atom_list1, &
362 subsys, mpi_comm_global, do_upper_diag=.true., do_lower=.false.)
363
364 END IF
365 CALL cp_fm_scale_and_add(1.0_dp, fm_cell1, 1.0_dp, fm_cell0)
366
367 ! symmetric matrix fm_cell0
368 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix_cells_raw(0)%matrix, fm_cell0, atom_list0, atom_list0, &
369 subsys, mpi_comm_global, do_upper_diag=.true., do_lower=.true.)
370
371 ! clean up
372 DEALLOCATE (c_to_i, i_to_c)
373 DO ic = 1, ncell
374 CALL dbcsr_release(mat_nosym(ic)%matrix)
375 END DO
376 CALL dbcsr_deallocate_matrix_set(mat_nosym)
377 DO rep = -2, 2
378 CALL dbcsr_deallocate_matrix(matrix_cells_raw(rep)%matrix)
379 END DO
380 DEALLOCATE (matrix_cells_raw)
381
382 CALL timestop(handle)
383 END SUBROUTINE negf_copy_contact_matrix
384
385! **************************************************************************************************
386!> \brief Extract part of the DBCSR matrix based on selected atoms and copy it into another DBCSR
387!> matrix.
388!> \param matrix_contact extracted DBCSR matrix
389!> \param matrix_device original DBCSR matrix
390!> \param atom_list list of selected atoms
391!> \param atom_map atomic map between device and contact force environments
392!> \param para_env parallel environment
393! **************************************************************************************************
394 SUBROUTINE negf_reference_contact_matrix(matrix_contact, matrix_device, atom_list, atom_map, para_env)
395 TYPE(dbcsr_type), POINTER :: matrix_contact, matrix_device
396 INTEGER, DIMENSION(:), INTENT(in) :: atom_list
397 TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
398 TYPE(mp_para_env_type), POINTER :: para_env
399
400 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_reference_contact_matrix'
401
402 INTEGER :: handle, i1, i2, iatom_col, iatom_row, &
403 icol, iproc, irow, max_atom, &
404 mepos_plus1, n1, n2, natoms, offset
405 INTEGER, ALLOCATABLE, DIMENSION(:) :: recv_nelems, send_nelems
406 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: rank_contact, rank_device
407 LOGICAL :: found, transp
408 REAL(kind=dp), DIMENSION(:, :), POINTER :: rblock
409 TYPE(mp_request_type), ALLOCATABLE, DIMENSION(:) :: recv_handlers, send_handlers
410 TYPE(negf_allocatable_rvector), ALLOCATABLE, &
411 DIMENSION(:) :: recv_packed_blocks, send_packed_blocks
412
413 CALL timeset(routinen, handle)
414 mepos_plus1 = para_env%mepos + 1
415
416 natoms = SIZE(atom_list)
417 max_atom = 0
418 DO iatom_row = 1, natoms
419 IF (atom_map(iatom_row)%iatom > max_atom) max_atom = atom_map(iatom_row)%iatom
420 END DO
421
422 ! find out which block goes to which node
423 ALLOCATE (rank_contact(max_atom, max_atom))
424 ALLOCATE (rank_device(max_atom, max_atom))
425
426 rank_contact(:, :) = 0
427 rank_device(:, :) = 0
428
429 DO iatom_col = 1, natoms
430 DO iatom_row = 1, iatom_col
431 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
432 icol = atom_map(iatom_col)%iatom
433 irow = atom_map(iatom_row)%iatom
434 ELSE
435 icol = atom_map(iatom_row)%iatom
436 irow = atom_map(iatom_col)%iatom
437 END IF
438
439 CALL dbcsr_get_block_p(matrix=matrix_device, &
440 row=atom_list(iatom_row), col=atom_list(iatom_col), &
441 block=rblock, found=found)
442 IF (found) rank_device(irow, icol) = mepos_plus1
443
444 CALL dbcsr_get_block_p(matrix=matrix_contact, row=irow, col=icol, block=rblock, found=found)
445 IF (found) rank_contact(irow, icol) = mepos_plus1
446 END DO
447 END DO
448
449 CALL para_env%sum(rank_device)
450 CALL para_env%sum(rank_contact)
451
452 ! compute number of packed matrix elements to send to / receive from each processor
453 ALLOCATE (recv_nelems(para_env%num_pe))
454 ALLOCATE (send_nelems(para_env%num_pe))
455 recv_nelems(:) = 0
456 send_nelems(:) = 0
457
458 DO iatom_col = 1, natoms
459 DO iatom_row = 1, iatom_col
460 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
461 icol = atom_map(iatom_col)%iatom
462 irow = atom_map(iatom_row)%iatom
463 ELSE
464 icol = atom_map(iatom_row)%iatom
465 irow = atom_map(iatom_col)%iatom
466 END IF
467
468 CALL dbcsr_get_block_p(matrix=matrix_device, &
469 row=atom_list(iatom_row), col=atom_list(iatom_col), &
470 block=rblock, found=found)
471 IF (found) THEN
472 iproc = rank_contact(irow, icol)
473 IF (iproc > 0) THEN
474 send_nelems(iproc) = send_nelems(iproc) + SIZE(rblock)
475 END IF
476 END IF
477
478 CALL dbcsr_get_block_p(matrix=matrix_contact, row=irow, col=icol, block=rblock, found=found)
479 IF (found) THEN
480 iproc = rank_device(irow, icol)
481 IF (iproc > 0) THEN
482 recv_nelems(iproc) = recv_nelems(iproc) + SIZE(rblock)
483 END IF
484 END IF
485 END DO
486 END DO
487
488 ! pack blocks
489 ALLOCATE (recv_packed_blocks(para_env%num_pe))
490 DO iproc = 1, para_env%num_pe
491 IF (iproc /= mepos_plus1 .AND. recv_nelems(iproc) > 0) THEN
492 ALLOCATE (recv_packed_blocks(iproc)%vector(recv_nelems(iproc)))
493 END IF
494 END DO
495
496 ALLOCATE (send_packed_blocks(para_env%num_pe))
497 DO iproc = 1, para_env%num_pe
498 IF (send_nelems(iproc) > 0) THEN
499 ALLOCATE (send_packed_blocks(iproc)%vector(send_nelems(iproc)))
500 END IF
501 END DO
502
503 send_nelems(:) = 0
504 DO iatom_col = 1, natoms
505 DO iatom_row = 1, iatom_col
506 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
507 icol = atom_map(iatom_col)%iatom
508 irow = atom_map(iatom_row)%iatom
509 transp = .false.
510 ELSE
511 icol = atom_map(iatom_row)%iatom
512 irow = atom_map(iatom_col)%iatom
513 transp = .true.
514 END IF
515
516 iproc = rank_contact(irow, icol)
517 IF (iproc > 0) THEN
518 CALL dbcsr_get_block_p(matrix=matrix_device, &
519 row=atom_list(iatom_row), col=atom_list(iatom_col), &
520 block=rblock, found=found)
521 IF (found) THEN
522 offset = send_nelems(iproc)
523 n1 = SIZE(rblock, 1)
524 n2 = SIZE(rblock, 2)
525
526 IF (transp) THEN
527 DO i1 = 1, n1
528 DO i2 = 1, n2
529 send_packed_blocks(iproc)%vector(offset + i2) = rblock(i1, i2)
530 END DO
531 offset = offset + n2
532 END DO
533 ELSE
534 DO i2 = 1, n2
535 DO i1 = 1, n1
536 send_packed_blocks(iproc)%vector(offset + i1) = rblock(i1, i2)
537 END DO
538 offset = offset + n1
539 END DO
540 END IF
541
542 send_nelems(iproc) = offset
543 END IF
544 END IF
545 END DO
546 END DO
547
548 ! send blocks
549 ALLOCATE (recv_handlers(para_env%num_pe), send_handlers(para_env%num_pe))
550
551 DO iproc = 1, para_env%num_pe
552 IF (iproc /= mepos_plus1 .AND. send_nelems(iproc) > 0) THEN
553 CALL para_env%isend(send_packed_blocks(iproc)%vector, iproc - 1, send_handlers(iproc), 1)
554 END IF
555 END DO
556
557 ! receive blocks
558 DO iproc = 1, para_env%num_pe
559 IF (iproc /= mepos_plus1) THEN
560 IF (recv_nelems(iproc) > 0) THEN
561 CALL para_env%irecv(recv_packed_blocks(iproc)%vector, iproc - 1, recv_handlers(iproc), 1)
562 END IF
563 ELSE
564 IF (ALLOCATED(send_packed_blocks(iproc)%vector)) THEN
565 CALL move_alloc(send_packed_blocks(iproc)%vector, recv_packed_blocks(iproc)%vector)
566 END IF
567 END IF
568 END DO
569
570 ! unpack blocks
571 DO iproc = 1, para_env%num_pe
572 IF (iproc /= mepos_plus1 .AND. recv_nelems(iproc) > 0) THEN
573 CALL recv_handlers(iproc)%wait()
574 END IF
575 END DO
576
577 recv_nelems(:) = 0
578 DO iatom_col = 1, natoms
579 DO iatom_row = 1, iatom_col
580 IF (atom_map(iatom_row)%iatom <= atom_map(iatom_col)%iatom) THEN
581 icol = atom_map(iatom_col)%iatom
582 irow = atom_map(iatom_row)%iatom
583 ELSE
584 icol = atom_map(iatom_row)%iatom
585 irow = atom_map(iatom_col)%iatom
586 END IF
587
588 iproc = rank_device(irow, icol)
589 IF (iproc > 0) THEN
590 CALL dbcsr_get_block_p(matrix=matrix_contact, row=irow, col=icol, block=rblock, found=found)
591
592 IF (found) THEN
593 offset = recv_nelems(iproc)
594 n1 = SIZE(rblock, 1)
595 n2 = SIZE(rblock, 2)
596
597 DO i2 = 1, n2
598 DO i1 = 1, n1
599 rblock(i1, i2) = recv_packed_blocks(iproc)%vector(offset + i1)
600 END DO
601 offset = offset + n1
602 END DO
603
604 recv_nelems(iproc) = offset
605 END IF
606 END IF
607 END DO
608 END DO
609
610 DO iproc = 1, para_env%num_pe
611 IF (iproc /= mepos_plus1 .AND. send_nelems(iproc) > 0) THEN
612 CALL send_handlers(iproc)%wait()
613 END IF
614 END DO
615
616 ! release memory
617 DEALLOCATE (recv_handlers, send_handlers)
618
619 DO iproc = para_env%num_pe, 1, -1
620 IF (ALLOCATED(send_packed_blocks(iproc)%vector)) THEN
621 DEALLOCATE (send_packed_blocks(iproc)%vector)
622 END IF
623 END DO
624 DEALLOCATE (send_packed_blocks)
625
626 DO iproc = para_env%num_pe, 1, -1
627 IF (ALLOCATED(recv_packed_blocks(iproc)%vector)) THEN
628 DEALLOCATE (recv_packed_blocks(iproc)%vector)
629 END IF
630 END DO
631 DEALLOCATE (recv_packed_blocks)
632
633 DEALLOCATE (rank_contact, rank_device)
634 CALL timestop(handle)
635 END SUBROUTINE negf_reference_contact_matrix
636
637! **************************************************************************************************
638!> \brief Invert cell_to_index mapping between unit cells and DBCSR matrix images.
639!> \param cell_to_index mapping: unit_cell -> image_index
640!> \param nimages number of images
641!> \param index_to_cell inverted mapping: image_index -> unit_cell
642!> \par History
643!> * 10.2017 created [Sergey Chulkov]
644! **************************************************************************************************
645 SUBROUTINE invert_cell_to_index(cell_to_index, nimages, index_to_cell)
646 INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index
647 INTEGER, INTENT(in) :: nimages
648 INTEGER, DIMENSION(3, nimages), INTENT(out) :: index_to_cell
649
650 CHARACTER(LEN=*), PARAMETER :: routinen = 'invert_cell_to_index'
651
652 INTEGER :: handle, i1, i2, i3, image
653 INTEGER, DIMENSION(3) :: lbounds, ubounds
654
655 CALL timeset(routinen, handle)
656
657 index_to_cell(:, :) = 0
658 lbounds = lbound(cell_to_index)
659 ubounds = ubound(cell_to_index)
660
661 DO i3 = lbounds(3), ubounds(3) ! z
662 DO i2 = lbounds(2), ubounds(2) ! y
663 DO i1 = lbounds(1), ubounds(1) ! x
664 image = cell_to_index(i1, i2, i3)
665 IF (image > 0 .AND. image <= nimages) THEN
666 index_to_cell(1, image) = i1
667 index_to_cell(2, image) = i2
668 index_to_cell(3, image) = i3
669 END IF
670 END DO
671 END DO
672 END DO
673
674 CALL timestop(handle)
675 END SUBROUTINE invert_cell_to_index
676
677! **************************************************************************************************
678!> \brief Helper routine to obtain index of a DBCSR matrix image by its unit cell replica.
679!> Can be used with any usin cell.
680!> \param cell indices of the unit cell
681!> \param cell_to_index mapping: unit_cell -> image_index
682!> \return DBCSR matrix images
683!> (0 means there are no non-zero matrix elements in the image)
684!> \par History
685!> * 10.2017 created [Sergey Chulkov]
686! **************************************************************************************************
687 PURE FUNCTION get_index_by_cell(cell, cell_to_index) RESULT(image)
688 INTEGER, DIMENSION(3), INTENT(in) :: cell
689 INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index
690 INTEGER :: image
691
692 IF (lbound(cell_to_index, 1) <= cell(1) .AND. ubound(cell_to_index, 1) >= cell(1) .AND. &
693 lbound(cell_to_index, 2) <= cell(2) .AND. ubound(cell_to_index, 2) >= cell(2) .AND. &
694 lbound(cell_to_index, 3) <= cell(3) .AND. ubound(cell_to_index, 3) >= cell(3)) THEN
695
696 image = cell_to_index(cell(1), cell(2), cell(3))
697 ELSE
698 image = 0
699 END IF
700 END FUNCTION get_index_by_cell
701
702! **************************************************************************************************
703!> \brief Desymmetrizes the KS or S matrices for one of spin components
704!> \param mat Hamiltonian or overlap matrices
705!> \param mat_nosym Desymmetrized Hamiltonian or overlap matrices
706!> \param cell_to_index Mapping of cell indices to linear RS indices
707!> \param index_to_cell Mapping of linear RS indices to cell indices
708!> \param kpoints Kpoint environment
709!> \par History
710!> * 05.2020 created [Fabian Ducry]
711!> * 11.2025 Modified for one spin component. [Dmitry Ryndyk]
712!> \author Fabian Ducry
713! **************************************************************************************************
714 SUBROUTINE desymmetrize_matrix(mat, mat_nosym, cell_to_index, index_to_cell, kpoints)
715 TYPE(dbcsr_p_type), DIMENSION(:), INTENT(IN), &
716 POINTER :: mat
717 TYPE(dbcsr_p_type), DIMENSION(:), INTENT(INOUT), &
718 POINTER :: mat_nosym
719 INTEGER, ALLOCATABLE, DIMENSION(:, :, :), &
720 INTENT(OUT) :: cell_to_index
721 INTEGER, ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: index_to_cell
722 TYPE(kpoint_type), INTENT(IN), POINTER :: kpoints
723
724 CHARACTER(len=*), PARAMETER :: routinen = 'desymmetrize_matrix'
725
726 INTEGER :: handle, iatom, ic, icn, icol, irow, &
727 jatom, ncell, nomirror, nx, ny, nz
728 INTEGER, DIMENSION(3) :: cell
729 INTEGER, DIMENSION(:, :), POINTER :: i2c
730 INTEGER, DIMENSION(:, :, :), POINTER :: c2i
731 LOGICAL :: found, lwtr
732 REAL(kind=dp), DIMENSION(:, :), POINTER :: block
734 DIMENSION(:), POINTER :: nl_iterator
735 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
736 POINTER :: sab_nl
737
738 CALL timeset(routinen, handle)
739
740 i2c => kpoints%index_to_cell
741 c2i => kpoints%cell_to_index
742
743 ncell = SIZE(i2c, 2)
744
745 nx = max(abs(lbound(c2i, 1)), abs(ubound(c2i, 1)))
746 ny = max(abs(lbound(c2i, 2)), abs(ubound(c2i, 3)))
747 nz = max(abs(lbound(c2i, 3)), abs(ubound(c2i, 3)))
748 ALLOCATE (cell_to_index(-nx:nx, -ny:ny, -nz:nz))
749 cell_to_index(lbound(c2i, 1):ubound(c2i, 1), &
750 lbound(c2i, 2):ubound(c2i, 2), &
751 lbound(c2i, 3):ubound(c2i, 3)) = c2i
752
753 ! identify cells with no mirror img
754 nomirror = 0
755 DO ic = 1, ncell
756 cell = i2c(:, ic)
757 IF (cell_to_index(-cell(1), -cell(2), -cell(3)) == 0) THEN
758 nomirror = nomirror + 1
759 END IF
760 END DO
761
762 ! create the mirror imgs
763 ALLOCATE (index_to_cell(3, ncell + nomirror))
764 index_to_cell(:, 1:ncell) = i2c
765
766 nomirror = 0 ! count the imgs without mirror
767 DO ic = 1, ncell
768 cell = index_to_cell(:, ic)
769 IF (cell_to_index(-cell(1), -cell(2), -cell(3)) == 0) THEN
770 nomirror = nomirror + 1
771 index_to_cell(:, ncell + nomirror) = -cell
772 cell_to_index(-cell(1), -cell(2), -cell(3)) = ncell + nomirror
773 END IF
774 END DO
775 ncell = ncell + nomirror
776
777 CALL get_kpoint_info(kpoints, sab_nl=sab_nl)
778 ! allocate the nonsymmetric matrices
779 NULLIFY (mat_nosym)
780 CALL dbcsr_allocate_matrix_set(mat_nosym, ncell)
781 DO ic = 1, ncell
782 ALLOCATE (mat_nosym(ic)%matrix)
783 CALL dbcsr_create(matrix=mat_nosym(ic)%matrix, &
784 template=mat(1)%matrix, &
785 matrix_type=dbcsr_type_no_symmetry)
786 CALL cp_dbcsr_alloc_block_from_nbl(mat_nosym(ic)%matrix, &
787 sab_nl, desymmetrize=.true.)
788 CALL dbcsr_set(mat_nosym(ic)%matrix, 0.0_dp)
789 END DO
790
791 ! desymmetrize the matrix for real space printing
792 CALL neighbor_list_iterator_create(nl_iterator, sab_nl)
793 DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
794 CALL get_iterator_info(nl_iterator, iatom=iatom, jatom=jatom, cell=cell)
795
796 ic = cell_to_index(cell(1), cell(2), cell(3))
797 icn = cell_to_index(-cell(1), -cell(2), -cell(3))
798 cpassert(icn > 0)
799
800 irow = iatom
801 icol = jatom
802 lwtr = .false.
803 ! always copy from the top
804 IF (iatom > jatom) THEN
805 irow = jatom
806 icol = iatom
807 lwtr = .true.
808 END IF
809
810 CALL dbcsr_get_block_p(matrix=mat(ic)%matrix, &
811 row=irow, col=icol, block=block, found=found)
812 cpassert(found)
813
814 ! copy to M(R) at (iatom,jatom)
815 ! copy to M(-R) at (jatom,iatom)
816 IF (lwtr) THEN
817 CALL dbcsr_put_block(matrix=mat_nosym(ic)%matrix, &
818 row=iatom, col=jatom, block=transpose(block))
819 CALL dbcsr_put_block(matrix=mat_nosym(icn)%matrix, &
820 row=jatom, col=iatom, block=block)
821 ELSE
822 CALL dbcsr_put_block(matrix=mat_nosym(ic)%matrix, &
823 row=iatom, col=jatom, block=block)
824 CALL dbcsr_put_block(matrix=mat_nosym(icn)%matrix, &
825 row=jatom, col=iatom, block=transpose(block))
826 END IF
827 END DO
828 CALL neighbor_list_iterator_release(nl_iterator)
829
830 DO ic = 1, ncell
831 CALL dbcsr_finalize(mat_nosym(ic)%matrix)
832 END DO
833
834 CALL timestop(handle)
835
836 END SUBROUTINE desymmetrize_matrix
837
838END 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, inversion_symmetry_only, symmetry_backend, symmetry_reduction_method, gamma_centered)
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, ncgf)
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.