(git:53a46e8)
Loading...
Searching...
No Matches
negf_env_types.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 Environment for NEGF based quantum transport calculations
10! **************************************************************************************************
12 USE cell_types, ONLY: cell_type,&
16 USE cp_dbcsr_api, ONLY: dbcsr_copy,&
24 USE cp_fm_types, ONLY: cp_fm_create,&
33 USE kinds, ONLY: default_string_length,&
34 dp
35 USE kpoint_types, ONLY: get_kpoint_env,&
52 USE pw_env_types, ONLY: pw_env_get,&
55 USE pw_types, ONLY: pw_r3d_rs_type
59 USE qs_energy, ONLY: qs_energies
63 USE qs_integrate_potential, ONLY: integrate_v_rspace
64 USE qs_mo_types, ONLY: get_mo_set,&
66 USE qs_rho_types, ONLY: qs_rho_get,&
70#include "./base/base_uses.f90"
71
72 IMPLICIT NONE
73 PRIVATE
74
75 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_env_types'
76 LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .true.
77
80
81! **************************************************************************************************
82!> \brief Contact-specific NEGF environment.
83!> \author Sergey Chulkov
84! **************************************************************************************************
86 REAL(kind=dp), DIMENSION(3) :: direction_vector = -1.0_dp, origin = -1.0_dp
87 REAL(kind=dp), DIMENSION(3) :: direction_vector_bias = -1.0_dp, origin_bias = -1.0_dp
88 !> an axis towards the secondary contact unit cell which coincides with the transport direction
89 !> 0 (undefined), 1 (+x), 2 (+y), 3 (+z), -1 (-x), -2 (-y), -3 (-z)
90 INTEGER :: direction_axis = -1
91 !> atoms belonging to a primary contact unit cell
92 INTEGER, ALLOCATABLE, DIMENSION(:) :: atomlist_cell0
93 !> atoms belonging to a secondary contact unit cell (will be removed one day ...)
94 INTEGER, ALLOCATABLE, DIMENSION(:) :: atomlist_cell1
95 !> list of equivalent atoms in an appropriate contact force environment
96 TYPE(negf_atom_map_type), ALLOCATABLE, &
97 DIMENSION(:) :: atom_map_cell0, atom_map_cell1
98 !> energy of the HOMO
99 REAL(kind=dp) :: homo_energy = -1.0_dp
100 !> diagonal (h_00) and off-diagonal (h_01) blocks of the contact Kohn-Sham matrix ([number_of_spins]).
101 !> The matrix h_01 is of the shape [nao_cell0 x nao_cell1]
102 TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: h_00, h_01
103 !> diagonal and off-diagonal blocks of the density matrix
104 TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: rho_00, rho_01
105 !> diagonal and off-diagonal blocks of the overlap matrix
106 TYPE(cp_fm_type), POINTER :: s_00 => null(), s_01 => null()
107 END TYPE negf_env_contact_type
108
109! **************************************************************************************************
110!> \brief NEGF environment.
111!> \author Sergey Chulkov
112! **************************************************************************************************
114 !> contact-specific NEGF environments
115 TYPE(negf_env_contact_type), ALLOCATABLE, &
116 DIMENSION(:) :: contacts
117 !> Kohn-Sham matrix of the scattering region
118 TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: h_s
119 !> Kohn-Sham matrix of the scattering region -- contact interface ([nspins, ncontacts])
120 TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :) :: h_sc
121 !> overlap matrix of the scattering region
122 TYPE(cp_fm_type), POINTER :: s_s => null()
123 !> an external Hartree potential in atomic basis set representation
124 TYPE(cp_fm_type), POINTER :: v_hartree_s => null()
125 !> overlap matrix of the scattering region -- contact interface for every contact ([ncontacts])
126 TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: s_sc
127 !> structure needed for density mixing
128 TYPE(mixing_storage_type), POINTER :: mixing_storage => null()
129 !> density mixing method
130 INTEGER :: mixing_method = -1
131 END TYPE negf_env_type
132
133! **************************************************************************************************
134!> \brief Allocatable list of the type 'negf_atom_map_type'.
135!> \author Sergey Chulkov
136! **************************************************************************************************
137 TYPE negf_atom_map_contact_type
138 TYPE(negf_atom_map_type), ALLOCATABLE, DIMENSION(:) :: atom_map
139 END TYPE negf_atom_map_contact_type
140
141CONTAINS
142
143! **************************************************************************************************
144!> \brief Create a new NEGF environment and compute the relevant Kohn-Sham matrices.
145!> \param negf_env NEGF environment to create
146!> \param sub_env NEGF parallel (sub)group environment
147!> \param negf_control NEGF control
148!> \param force_env the primary force environment
149!> \param negf_mixing_section pointer to a mixing section within the NEGF input section
150!> \param log_unit output unit number
151!> \par History
152!> * 01.2017 created [Sergey Chulkov]
153! **************************************************************************************************
154 SUBROUTINE negf_env_create(negf_env, sub_env, negf_control, force_env, negf_mixing_section, log_unit)
155 TYPE(negf_env_type), INTENT(inout) :: negf_env
156 TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
157 TYPE(negf_control_type), POINTER :: negf_control
158 TYPE(force_env_type), POINTER :: force_env
159 TYPE(section_vals_type), POINTER :: negf_mixing_section
160 INTEGER, INTENT(in) :: log_unit
161
162 CHARACTER(len=*), PARAMETER :: routinen = 'negf_env_create'
163
164 CHARACTER(len=default_string_length) :: contact_str, force_env_str, &
165 n_force_env_str
166 INTEGER :: handle, icontact, in_use, n_force_env, &
167 ncontacts
168 LOGICAL :: do_kpoints
169 TYPE(cp_blacs_env_type), POINTER :: blacs_env
170 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp
171 TYPE(dft_control_type), POINTER :: dft_control
172 TYPE(force_env_p_type), DIMENSION(:), POINTER :: sub_force_env
173 TYPE(negf_atom_map_contact_type), ALLOCATABLE, &
174 DIMENSION(:) :: map_contact
175 TYPE(pw_r3d_rs_type), POINTER :: v_hartree_rspace
176 TYPE(qs_environment_type), POINTER :: qs_env, qs_env_contact
177 TYPE(qs_subsys_type), POINTER :: subsys, subsys_contact
178
179 CALL timeset(routinen, handle)
180
181 ! ensure we have Quickstep enabled for all force_env
182 NULLIFY (sub_force_env)
183 CALL force_env_get(force_env, in_use=in_use, qs_env=qs_env, sub_force_env=sub_force_env)
184
185 IF (ASSOCIATED(sub_force_env)) THEN
186 n_force_env = SIZE(sub_force_env)
187 ELSE
188 n_force_env = 0
189 END IF
190
191 IF (in_use == use_qs_force) THEN
192 DO icontact = 1, n_force_env
193 CALL force_env_get(sub_force_env(icontact)%force_env, in_use=in_use)
194 IF (in_use /= use_qs_force) EXIT
195 END DO
196 END IF
197
198 IF (in_use /= use_qs_force) THEN
199 cpabort("Quickstep is required for NEGF run.")
200 END IF
201
202 ! check that all mentioned FORCE_EVAL sections are actually present
203 ncontacts = SIZE(negf_control%contacts)
204
205 DO icontact = 1, ncontacts
206 IF (negf_control%contacts(icontact)%force_env_index > n_force_env) THEN
207 WRITE (contact_str, '(I11)') icontact
208 WRITE (force_env_str, '(I11)') negf_control%contacts(icontact)%force_env_index
209 WRITE (n_force_env_str, '(I11)') n_force_env
210
211 CALL cp_abort(__location__, &
212 "Contact number "//trim(adjustl(contact_str))//" is linked with the FORCE_EVAL section number "// &
213 trim(adjustl(force_env_str))//", however only "//trim(adjustl(n_force_env_str))// &
214 " FORCE_EVAL sections have been found. Note that FORCE_EVAL sections are enumerated from 0"// &
215 " and that the primary (0-th) section must contain all the atoms.")
216 END IF
217 END DO
218
219 ! create basic matrices and neighbour lists for the primary force_env,
220 ! so we know how matrix elements are actually distributed across CPUs.
221 CALL qs_energies_init(qs_env, calc_forces=.false.)
222 CALL get_qs_env(qs_env, blacs_env=blacs_env, do_kpoints=do_kpoints, &
223 matrix_s_kp=matrix_s_kp, matrix_ks_kp=matrix_ks_kp, &
224 subsys=subsys, v_hartree_rspace=v_hartree_rspace)
225
226 IF (do_kpoints) THEN
227 cpabort("k-points are currently not supported for device FORCE_EVAL")
228 END IF
229
230 ! stage 1: map the atoms between the device force_env and all contact force_env-s
231 ALLOCATE (negf_env%contacts(ncontacts))
232 ALLOCATE (map_contact(ncontacts))
233
234 DO icontact = 1, ncontacts
235 IF (negf_control%contacts(icontact)%force_env_index > 0) THEN
236 CALL force_env_get(sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, qs_env=qs_env_contact)
237 CALL get_qs_env(qs_env_contact, subsys=subsys_contact)
238
239 CALL negf_env_contact_init_maps(contact_env=negf_env%contacts(icontact), &
240 contact_control=negf_control%contacts(icontact), &
241 atom_map=map_contact(icontact)%atom_map, &
242 eps_geometry=negf_control%eps_geometry, &
243 subsys_device=subsys, &
244 subsys_contact=subsys_contact)
245
246 IF (negf_env%contacts(icontact)%direction_axis == 0) THEN
247 WRITE (contact_str, '(I11)') icontact
248 WRITE (force_env_str, '(I11)') negf_control%contacts(icontact)%force_env_index
249 CALL cp_abort(__location__, &
250 "One lattice vector of the contact unit cell (FORCE_EVAL section "// &
251 trim(adjustl(force_env_str))//") must be parallel to the direction of the contact "// &
252 trim(adjustl(contact_str))//".")
253 END IF
254 END IF
255 END DO
256
257 ! stage 2: obtain relevant Kohn-Sham matrix blocks for each contact (separate bulk DFT calculation)
258 DO icontact = 1, ncontacts
259 IF (negf_control%contacts(icontact)%force_env_index > 0) THEN
260 IF (log_unit > 0) &
261 WRITE (log_unit, '(/,T2,A,T70,I11)') "NEGF| Construct the Kohn-Sham matrix for the contact", icontact
262
263 CALL force_env_get(sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, qs_env=qs_env_contact)
264
265 CALL qs_energies(qs_env_contact, consistent_energies=.false., calc_forces=.false.)
266
267 CALL negf_env_contact_init_matrices(contact_env=negf_env%contacts(icontact), sub_env=sub_env, &
268 qs_env_contact=qs_env_contact)
269 IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
270 END IF
271 END DO
272
273 ! obtain an initial KS-matrix for the scattering region
274 IF (log_unit > 0) &
275 WRITE (log_unit, '(/,T2,A,T70)') "NEGF| Construct the Kohn-Sham matrix for the entire system"
276 CALL qs_energies(qs_env, consistent_energies=.false., calc_forces=.false.)
277 IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
278
279 ! *** obtain relevant Kohn-Sham matrix blocks for each contact with no separate FORCE_ENV ***
280 DO icontact = 1, ncontacts
281 IF (negf_control%contacts(icontact)%force_env_index <= 0) THEN
282 CALL negf_env_contact_init_matrices_gamma(contact_env=negf_env%contacts(icontact), &
283 contact_control=negf_control%contacts(icontact), &
284 sub_env=sub_env, qs_env=qs_env, &
285 eps_geometry=negf_control%eps_geometry)
286 END IF
287 END DO
288
289 ! extract device-related matrix blocks
290 CALL negf_env_device_init_matrices(negf_env, negf_control, sub_env, qs_env)
291
292 ! electron density mixing;
293 ! the input section below should be consistent with the subroutine create_negf_section()
294 NULLIFY (negf_env%mixing_storage)
295 CALL section_vals_val_get(negf_mixing_section, "METHOD", i_val=negf_env%mixing_method)
296
297 CALL get_qs_env(qs_env, dft_control=dft_control)
298 ALLOCATE (negf_env%mixing_storage)
299 CALL mixing_storage_create(negf_env%mixing_storage, negf_mixing_section, &
300 negf_env%mixing_method, dft_control%qs_control%cutoff)
301
302 CALL timestop(handle)
303 END SUBROUTINE negf_env_create
304
305! **************************************************************************************************
306!> \brief Establish mapping between the primary and the contact force environments
307!> \param contact_env NEGF environment for the given contact (modified on exit)
308!> \param contact_control NEGF control
309!> \param atom_map atomic map
310!> \param eps_geometry accuracy in mapping atoms between different force environments
311!> \param subsys_device QuickStep subsystem of the device force environment
312!> \param subsys_contact QuickStep subsystem of the contact force environment
313!> \author Sergey Chulkov
314! **************************************************************************************************
315 SUBROUTINE negf_env_contact_init_maps(contact_env, contact_control, atom_map, &
316 eps_geometry, subsys_device, subsys_contact)
317 TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
318 TYPE(negf_control_contact_type), INTENT(in) :: contact_control
319 TYPE(negf_atom_map_type), ALLOCATABLE, &
320 DIMENSION(:), INTENT(inout) :: atom_map
321 REAL(kind=dp), INTENT(in) :: eps_geometry
322 TYPE(qs_subsys_type), POINTER :: subsys_device, subsys_contact
323
324 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_env_contact_init_maps'
325
326 INTEGER :: handle, natoms
327
328 CALL timeset(routinen, handle)
329
330 CALL contact_direction_vector(contact_env%origin, &
331 contact_env%direction_vector, &
332 contact_env%origin_bias, &
333 contact_env%direction_vector_bias, &
334 contact_control%atomlist_screening, &
335 contact_control%atomlist_bulk, &
336 subsys_device)
337
338 contact_env%direction_axis = contact_direction_axis(contact_env%direction_vector, subsys_contact, eps_geometry)
339
340 IF (contact_env%direction_axis /= 0) THEN
341 natoms = SIZE(contact_control%atomlist_bulk)
342 ALLOCATE (atom_map(natoms))
343
344 ! map atom listed in 'contact_control%atomlist_bulk' to the corresponding atom/cell replica from the contact force_env
345 CALL negf_map_atomic_indices(atom_map=atom_map, &
346 atom_list=contact_control%atomlist_bulk, &
347 subsys_device=subsys_device, &
348 subsys_contact=subsys_contact, &
349 eps_geometry=eps_geometry)
350
351 ! list atoms from 'contact_control%atomlist_bulk' which belong to
352 ! the primary unit cell of the bulk region for the given contact
353 CALL list_atoms_in_bulk_primary_unit_cell(atomlist_cell0=contact_env%atomlist_cell0, &
354 atom_map_cell0=contact_env%atom_map_cell0, &
355 atomlist_bulk=contact_control%atomlist_bulk, &
356 atom_map=atom_map, &
357 origin=contact_env%origin, &
358 direction_vector=contact_env%direction_vector, &
359 direction_axis=contact_env%direction_axis, &
360 subsys_device=subsys_device)
361
362 ! secondary unit cell
363 CALL list_atoms_in_bulk_secondary_unit_cell(atomlist_cell1=contact_env%atomlist_cell1, &
364 atom_map_cell1=contact_env%atom_map_cell1, &
365 atomlist_bulk=contact_control%atomlist_bulk, &
366 atom_map=atom_map, &
367 origin=contact_env%origin, &
368 direction_vector=contact_env%direction_vector, &
369 direction_axis=contact_env%direction_axis, &
370 subsys_device=subsys_device)
371 END IF
372
373 CALL timestop(handle)
374 END SUBROUTINE negf_env_contact_init_maps
375
376! **************************************************************************************************
377!> \brief Extract relevant matrix blocks for the given contact.
378!> \param contact_env NEGF environment for the contact (modified on exit)
379!> \param sub_env NEGF parallel (sub)group environment
380!> \param qs_env_contact QuickStep environment for the contact force environment
381!> \par History
382!> * 10.2017 created [Sergey Chulkov]
383!> * 10.2025 The subroutine is essentially modified. New functionality of negf_copy_contact_matrix.
384!> [Dmitry Ryndyk]
385! **************************************************************************************************
386 SUBROUTINE negf_env_contact_init_matrices(contact_env, sub_env, qs_env_contact)
387 TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
388 TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
389 TYPE(qs_environment_type), POINTER :: qs_env_contact
390
391 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_env_contact_init_matrices'
392
393 INTEGER :: handle, iatom, ispin, nao, natoms, &
394 nimages, nspins
395 INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_list0, atom_list1
396 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: index_to_cell
397 INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index
398 LOGICAL :: do_kpoints
399 TYPE(cp_fm_struct_type), POINTER :: fm_struct
400 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matkp
401 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp, rho_ao_kp
402 TYPE(dft_control_type), POINTER :: dft_control
403 TYPE(kpoint_type), POINTER :: kpoints
404 TYPE(mp_para_env_type), POINTER :: para_env
405 TYPE(qs_rho_type), POINTER :: rho_struct
406 TYPE(qs_subsys_type), POINTER :: subsys
407
408 CALL timeset(routinen, handle)
409
410 CALL get_qs_env(qs_env_contact, &
411 dft_control=dft_control, &
412 do_kpoints=do_kpoints, &
413 kpoints=kpoints, &
414 matrix_ks_kp=matrix_ks_kp, &
415 matrix_s_kp=matrix_s_kp, &
416 para_env=para_env, &
417 rho=rho_struct, &
418 subsys=subsys)
419 CALL qs_rho_get(rho_struct, rho_ao_kp=rho_ao_kp)
420
421 CALL negf_homo_energy_estimate(contact_env%homo_energy, qs_env_contact)
422
423 natoms = SIZE(contact_env%atomlist_cell0)
424 ALLOCATE (atom_list0(natoms))
425 DO iatom = 1, natoms
426 atom_list0(iatom) = contact_env%atom_map_cell0(iatom)%iatom
427
428 ! with no k-points there is one-to-one correspondence between the primary unit cell
429 ! of the contact force_env and the first contact unit cell of the device force_env
430 IF (sum(abs(contact_env%atom_map_cell0(iatom)%cell(:))) > 0) THEN
431 cpabort("NEGF K-points are not currently supported")
432 END IF
433 END DO
434
435 cpassert(SIZE(contact_env%atomlist_cell1) == natoms)
436 ALLOCATE (atom_list1(natoms))
437 DO iatom = 1, natoms
438 atom_list1(iatom) = contact_env%atom_map_cell1(iatom)%iatom
439 END DO
440
441 nspins = dft_control%nspins
442 nimages = dft_control%nimages
443
444 IF (do_kpoints) THEN
445 CALL get_kpoint_info(kpoints, cell_to_index=cell_to_index)
446 ELSE
447 ALLOCATE (cell_to_index(0:0, 0:0, 0:0))
448 cell_to_index(0, 0, 0) = 1
449 END IF
450
451 ALLOCATE (index_to_cell(3, nimages))
452 CALL invert_cell_to_index(cell_to_index, nimages, index_to_cell)
453 IF (.NOT. do_kpoints) DEALLOCATE (cell_to_index)
454
455 NULLIFY (fm_struct)
456 nao = number_of_atomic_orbitals(subsys, atom_list0)
457 CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nao, context=sub_env%blacs_env)
458
459 ! ++ create matrices: s_00, s_01
460 ALLOCATE (contact_env%s_00, contact_env%s_01)
461 CALL cp_fm_create(contact_env%s_00, fm_struct)
462 CALL cp_fm_create(contact_env%s_01, fm_struct)
463
464 ! ++ create matrices: h_00, h_01, rho_00, rho_01
465 ALLOCATE (contact_env%h_00(nspins), contact_env%h_01(nspins))
466 ALLOCATE (contact_env%rho_00(nspins), contact_env%rho_01(nspins))
467 DO ispin = 1, nspins
468 CALL cp_fm_create(contact_env%h_00(ispin), fm_struct)
469 CALL cp_fm_create(contact_env%h_01(ispin), fm_struct)
470 CALL cp_fm_create(contact_env%rho_00(ispin), fm_struct)
471 CALL cp_fm_create(contact_env%rho_01(ispin), fm_struct)
472 END DO
473
474 CALL cp_fm_struct_release(fm_struct)
475
476 ! extract matrices: s_00, s_01
477 matkp => matrix_s_kp(1, :)
478 CALL negf_copy_contact_matrix(fm_cell0=contact_env%s_00, &
479 fm_cell1=contact_env%s_01, &
480 direction_axis=contact_env%direction_axis, &
481 matrix_kp=matkp, &
482 atom_list0=atom_list0, atom_list1=atom_list1, &
483 subsys=subsys, mpi_comm_global=para_env, &
484 kpoints=kpoints)
485
486 ! extract matrices: h_00, h_01, rho_00, rho_01
487 DO ispin = 1, nspins
488 matkp => matrix_ks_kp(ispin, :)
489 CALL negf_copy_contact_matrix(fm_cell0=contact_env%h_00(ispin), &
490 fm_cell1=contact_env%h_01(ispin), &
491 direction_axis=contact_env%direction_axis, &
492 matrix_kp=matkp, &
493 atom_list0=atom_list0, atom_list1=atom_list1, &
494 subsys=subsys, mpi_comm_global=para_env, &
495 kpoints=kpoints)
496
497 matkp => rho_ao_kp(ispin, :)
498 CALL negf_copy_contact_matrix(fm_cell0=contact_env%rho_00(ispin), &
499 fm_cell1=contact_env%rho_01(ispin), &
500 direction_axis=contact_env%direction_axis, &
501 matrix_kp=matkp, &
502 atom_list0=atom_list0, atom_list1=atom_list1, &
503 subsys=subsys, mpi_comm_global=para_env, &
504 kpoints=kpoints)
505 END DO
506
507 DEALLOCATE (atom_list0, atom_list1)
508
509 CALL timestop(handle)
510 END SUBROUTINE negf_env_contact_init_matrices
511
512! **************************************************************************************************
513!> \brief Extract relevant matrix blocks for the given contact using the device's force environment.
514!> \param contact_env NEGF environment for the contact (modified on exit)
515!> \param contact_control NEGF control for the contact
516!> \param sub_env NEGF parallel (sub)group environment
517!> \param qs_env QuickStep environment for the device force environment
518!> \param eps_geometry accuracy in Cartesian coordinates
519!> \author Sergey Chulkov
520! **************************************************************************************************
521 SUBROUTINE negf_env_contact_init_matrices_gamma(contact_env, contact_control, sub_env, qs_env, eps_geometry)
522 TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
523 TYPE(negf_control_contact_type), INTENT(in) :: contact_control
524 TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
525 TYPE(qs_environment_type), POINTER :: qs_env
526 REAL(kind=dp), INTENT(in) :: eps_geometry
527
528 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_env_contact_init_matrices_gamma'
529
530 INTEGER :: handle, iatom, icell, ispin, nao_c, &
531 nspins
532 LOGICAL :: do_kpoints
533 REAL(kind=dp), DIMENSION(2) :: r2_origin_cell
534 REAL(kind=dp), DIMENSION(3) :: direction_vector, origin
535 TYPE(cp_fm_struct_type), POINTER :: fm_struct
536 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp, rho_ao_kp
537 TYPE(dft_control_type), POINTER :: dft_control
538 TYPE(mp_para_env_type), POINTER :: para_env
539 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
540 TYPE(qs_rho_type), POINTER :: rho_struct
541 TYPE(qs_subsys_type), POINTER :: subsys
542
543 CALL timeset(routinen, handle)
544
545 CALL get_qs_env(qs_env, &
546 dft_control=dft_control, &
547 do_kpoints=do_kpoints, &
548 matrix_ks_kp=matrix_ks_kp, &
549 matrix_s_kp=matrix_s_kp, &
550 para_env=para_env, &
551 rho=rho_struct, &
552 subsys=subsys)
553 CALL qs_rho_get(rho_struct, rho_ao_kp=rho_ao_kp)
554
555 IF (do_kpoints) THEN
556 CALL cp_abort(__location__, &
557 "K-points in device region have not been implemented yet.")
558 END IF
559
560 nspins = dft_control%nspins
561
562 nao_c = number_of_atomic_orbitals(subsys, contact_control%atomlist_cell(1)%vector)
563 IF (number_of_atomic_orbitals(subsys, contact_control%atomlist_cell(2)%vector) /= nao_c) THEN
564 CALL cp_abort(__location__, &
565 "Primary and secondary bulk contact cells should be identical "// &
566 "in terms of the number of atoms of each kind, and their basis sets. "// &
567 "No single atom, however, can be shared between these two cells.")
568 END IF
569
570 contact_env%homo_energy = 0.0_dp
571
572 CALL contact_direction_vector(contact_env%origin, &
573 contact_env%direction_vector, &
574 contact_env%origin_bias, &
575 contact_env%direction_vector_bias, &
576 contact_control%atomlist_screening, &
577 contact_control%atomlist_bulk, &
578 subsys)
579
580 contact_env%direction_axis = contact_direction_axis(contact_env%direction_vector, subsys, eps_geometry)
581
582 ! choose the primary and secondary contact unit cells
583 CALL qs_subsys_get(subsys, particle_set=particle_set)
584
585 origin = particle_set(contact_control%atomlist_screening(1))%r
586 DO iatom = 2, SIZE(contact_control%atomlist_screening)
587 origin = origin + particle_set(contact_control%atomlist_screening(iatom))%r
588 END DO
589 origin = origin/real(SIZE(contact_control%atomlist_screening), kind=dp)
590
591 DO icell = 1, 2
592 direction_vector = particle_set(contact_control%atomlist_cell(icell)%vector(1))%r
593 DO iatom = 2, SIZE(contact_control%atomlist_cell(icell)%vector)
594 direction_vector = direction_vector + particle_set(contact_control%atomlist_cell(icell)%vector(iatom))%r
595 END DO
596 direction_vector = direction_vector/real(SIZE(contact_control%atomlist_cell(icell)%vector), kind=dp)
597 direction_vector = direction_vector - origin
598 r2_origin_cell(icell) = dot_product(direction_vector, direction_vector)
599 END DO
600
601 IF (abs(r2_origin_cell(1) - r2_origin_cell(2)) < (eps_geometry*eps_geometry)) THEN
602 ! primary and secondary bulk unit cells should not overlap;
603 ! currently we check that they are different by at least one atom that is, indeed, not sufficient.
604 CALL cp_abort(__location__, &
605 "Primary and secondary bulk contact cells should not overlap ")
606 ELSE IF (r2_origin_cell(1) < r2_origin_cell(2)) THEN
607 ALLOCATE (contact_env%atomlist_cell0(SIZE(contact_control%atomlist_cell(1)%vector)))
608 contact_env%atomlist_cell0(:) = contact_control%atomlist_cell(1)%vector(:)
609 ALLOCATE (contact_env%atomlist_cell1(SIZE(contact_control%atomlist_cell(2)%vector)))
610 contact_env%atomlist_cell1(:) = contact_control%atomlist_cell(2)%vector(:)
611 ELSE
612 ALLOCATE (contact_env%atomlist_cell0(SIZE(contact_control%atomlist_cell(2)%vector)))
613 contact_env%atomlist_cell0(:) = contact_control%atomlist_cell(2)%vector(:)
614 ALLOCATE (contact_env%atomlist_cell1(SIZE(contact_control%atomlist_cell(1)%vector)))
615 contact_env%atomlist_cell1(:) = contact_control%atomlist_cell(1)%vector(:)
616 END IF
617
618 NULLIFY (fm_struct)
619 CALL cp_fm_struct_create(fm_struct, nrow_global=nao_c, ncol_global=nao_c, context=sub_env%blacs_env)
620 ALLOCATE (contact_env%h_00(nspins), contact_env%h_01(nspins))
621 ALLOCATE (contact_env%rho_00(nspins), contact_env%rho_01(nspins))
622 DO ispin = 1, nspins
623 CALL cp_fm_create(contact_env%h_00(ispin), fm_struct)
624 CALL cp_fm_create(contact_env%h_01(ispin), fm_struct)
625 CALL cp_fm_create(contact_env%rho_00(ispin), fm_struct)
626 CALL cp_fm_create(contact_env%rho_01(ispin), fm_struct)
627 END DO
628 ALLOCATE (contact_env%s_00, contact_env%s_01)
629 CALL cp_fm_create(contact_env%s_00, fm_struct)
630 CALL cp_fm_create(contact_env%s_01, fm_struct)
631 CALL cp_fm_struct_release(fm_struct)
632
633 DO ispin = 1, nspins
634 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
635 fm=contact_env%h_00(ispin), &
636 atomlist_row=contact_env%atomlist_cell0, &
637 atomlist_col=contact_env%atomlist_cell0, &
638 subsys=subsys, mpi_comm_global=para_env, &
639 do_upper_diag=.true., do_lower=.true.)
640 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
641 fm=contact_env%h_01(ispin), &
642 atomlist_row=contact_env%atomlist_cell0, &
643 atomlist_col=contact_env%atomlist_cell1, &
644 subsys=subsys, mpi_comm_global=para_env, &
645 do_upper_diag=.true., do_lower=.true.)
646
647 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=rho_ao_kp(ispin, 1)%matrix, &
648 fm=contact_env%rho_00(ispin), &
649 atomlist_row=contact_env%atomlist_cell0, &
650 atomlist_col=contact_env%atomlist_cell0, &
651 subsys=subsys, mpi_comm_global=para_env, &
652 do_upper_diag=.true., do_lower=.true.)
653 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=rho_ao_kp(ispin, 1)%matrix, &
654 fm=contact_env%rho_01(ispin), &
655 atomlist_row=contact_env%atomlist_cell0, &
656 atomlist_col=contact_env%atomlist_cell1, &
657 subsys=subsys, mpi_comm_global=para_env, &
658 do_upper_diag=.true., do_lower=.true.)
659 END DO
660
661 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
662 fm=contact_env%s_00, &
663 atomlist_row=contact_env%atomlist_cell0, &
664 atomlist_col=contact_env%atomlist_cell0, &
665 subsys=subsys, mpi_comm_global=para_env, &
666 do_upper_diag=.true., do_lower=.true.)
667 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
668 fm=contact_env%s_01, &
669 atomlist_row=contact_env%atomlist_cell0, &
670 atomlist_col=contact_env%atomlist_cell1, &
671 subsys=subsys, mpi_comm_global=para_env, &
672 do_upper_diag=.true., do_lower=.true.)
673
674 CALL timestop(handle)
675 END SUBROUTINE negf_env_contact_init_matrices_gamma
676
677! **************************************************************************************************
678!> \brief Extract relevant matrix blocks for the scattering region as well as
679!> all the scattering -- contact interface regions.
680!> \param negf_env NEGF environment (modified on exit)
681!> \param negf_control NEGF control
682!> \param sub_env NEGF parallel (sub)group environment
683!> \param qs_env Primary QuickStep environment
684!> \author Sergey Chulkov
685! **************************************************************************************************
686 SUBROUTINE negf_env_device_init_matrices(negf_env, negf_control, sub_env, qs_env)
687 TYPE(negf_env_type), INTENT(inout) :: negf_env
688 TYPE(negf_control_type), POINTER :: negf_control
689 TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
690 TYPE(qs_environment_type), POINTER :: qs_env
691
692 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_env_device_init_matrices'
693
694 INTEGER :: handle, icontact, ispin, nao_c, nao_s, &
695 ncontacts, nspins
696 LOGICAL :: do_kpoints
697 TYPE(cp_fm_struct_type), POINTER :: fm_struct
698 TYPE(dbcsr_p_type) :: hmat
699 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp
700 TYPE(dft_control_type), POINTER :: dft_control
701 TYPE(mp_para_env_type), POINTER :: para_env
702 TYPE(pw_env_type), POINTER :: pw_env
703 TYPE(pw_pool_type), POINTER :: pw_pool
704 TYPE(pw_r3d_rs_type) :: v_hartree
705 TYPE(qs_subsys_type), POINTER :: subsys
706
707 CALL timeset(routinen, handle)
708
709 IF (ALLOCATED(negf_control%atomlist_S_screening)) THEN
710 CALL get_qs_env(qs_env, &
711 dft_control=dft_control, &
712 do_kpoints=do_kpoints, &
713 matrix_ks_kp=matrix_ks_kp, &
714 matrix_s_kp=matrix_s_kp, &
715 para_env=para_env, &
716 pw_env=pw_env, &
717 subsys=subsys)
718 CALL pw_env_get(pw_env, auxbas_pw_pool=pw_pool)
719
720 IF (do_kpoints) THEN
721 CALL cp_abort(__location__, &
722 "K-points in device region have not been implemented yet.")
723 END IF
724
725 ncontacts = SIZE(negf_control%contacts)
726 nspins = dft_control%nspins
727
728 NULLIFY (fm_struct)
729 nao_s = number_of_atomic_orbitals(subsys, negf_control%atomlist_S_screening)
730
731 ! ++ create matrices: h_s, s_s
732 NULLIFY (negf_env%s_s, negf_env%v_hartree_s, fm_struct)
733 ALLOCATE (negf_env%h_s(nspins))
734
735 CALL cp_fm_struct_create(fm_struct, nrow_global=nao_s, ncol_global=nao_s, context=sub_env%blacs_env)
736 ALLOCATE (negf_env%s_s)
737 CALL cp_fm_create(negf_env%s_s, fm_struct)
738 DO ispin = 1, nspins
739 CALL cp_fm_create(negf_env%h_s(ispin), fm_struct)
740 END DO
741 ALLOCATE (negf_env%v_hartree_s)
742 CALL cp_fm_create(negf_env%v_hartree_s, fm_struct)
743 CALL cp_fm_struct_release(fm_struct)
744
745 ! ++ create matrices: h_sc, s_sc
746 ALLOCATE (negf_env%h_sc(nspins, ncontacts), negf_env%s_sc(ncontacts))
747 DO icontact = 1, ncontacts
748 nao_c = number_of_atomic_orbitals(subsys, negf_env%contacts(icontact)%atomlist_cell0)
749 CALL cp_fm_struct_create(fm_struct, nrow_global=nao_s, ncol_global=nao_c, context=sub_env%blacs_env)
750
751 CALL cp_fm_create(negf_env%s_sc(icontact), fm_struct)
752
753 DO ispin = 1, nspins
754 CALL cp_fm_create(negf_env%h_sc(ispin, icontact), fm_struct)
755 END DO
756
757 CALL cp_fm_struct_release(fm_struct)
758 END DO
759
760 ! extract matrices: h_s, s_s
761 DO ispin = 1, nspins
762 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
763 fm=negf_env%h_s(ispin), &
764 atomlist_row=negf_control%atomlist_S_screening, &
765 atomlist_col=negf_control%atomlist_S_screening, &
766 subsys=subsys, mpi_comm_global=para_env, &
767 do_upper_diag=.true., do_lower=.true.)
768 END DO
769
770 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
771 fm=negf_env%s_s, &
772 atomlist_row=negf_control%atomlist_S_screening, &
773 atomlist_col=negf_control%atomlist_S_screening, &
774 subsys=subsys, mpi_comm_global=para_env, &
775 do_upper_diag=.true., do_lower=.true.)
776
777 ! v_hartree_s
778 NULLIFY (hmat%matrix)
779 CALL dbcsr_init_p(hmat%matrix)
780 CALL dbcsr_copy(matrix_b=hmat%matrix, matrix_a=matrix_s_kp(1, 1)%matrix)
781 CALL dbcsr_set(hmat%matrix, 0.0_dp)
782
783 CALL pw_pool%create_pw(v_hartree)
784 CALL negf_env_init_v_hartree(v_hartree, negf_env%contacts, negf_control%contacts)
785
786 CALL integrate_v_rspace(v_rspace=v_hartree, hmat=hmat, qs_env=qs_env, &
787 calculate_forces=.false., compute_tau=.false., gapw=.false.)
788
789 CALL pw_pool%give_back_pw(v_hartree)
790
791 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=hmat%matrix, &
792 fm=negf_env%v_hartree_s, &
793 atomlist_row=negf_control%atomlist_S_screening, &
794 atomlist_col=negf_control%atomlist_S_screening, &
795 subsys=subsys, mpi_comm_global=para_env, &
796 do_upper_diag=.true., do_lower=.true.)
797
798 CALL dbcsr_deallocate_matrix(hmat%matrix)
799
800 ! extract matrices: h_sc, s_sc
801 DO icontact = 1, ncontacts
802 DO ispin = 1, nspins
803 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
804 fm=negf_env%h_sc(ispin, icontact), &
805 atomlist_row=negf_control%atomlist_S_screening, &
806 atomlist_col=negf_env%contacts(icontact)%atomlist_cell0, &
807 subsys=subsys, mpi_comm_global=para_env, &
808 do_upper_diag=.true., do_lower=.true.)
809 END DO
810
811 CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
812 fm=negf_env%s_sc(icontact), &
813 atomlist_row=negf_control%atomlist_S_screening, &
814 atomlist_col=negf_env%contacts(icontact)%atomlist_cell0, &
815 subsys=subsys, mpi_comm_global=para_env, &
816 do_upper_diag=.true., do_lower=.true.)
817 END DO
818 END IF
819
820 CALL timestop(handle)
821 END SUBROUTINE negf_env_device_init_matrices
822
823! **************************************************************************************************
824!> \brief Contribution to the Hartree potential related to the external bias voltage.
825!> \param v_hartree Hartree potential (modified on exit)
826!> \param contact_env NEGF environment for every contact
827!> \param contact_control NEGF control for every contact
828!> \author Sergey Chulkov
829! **************************************************************************************************
830 SUBROUTINE negf_env_init_v_hartree(v_hartree, contact_env, contact_control)
831 TYPE(pw_r3d_rs_type), INTENT(IN) :: v_hartree
832 TYPE(negf_env_contact_type), DIMENSION(:), &
833 INTENT(in) :: contact_env
834 TYPE(negf_control_contact_type), DIMENSION(:), &
835 INTENT(in) :: contact_control
836
837 CHARACTER(len=*), PARAMETER :: routinen = 'negf_env_init_v_hartree'
838 REAL(kind=dp), PARAMETER :: threshold = 16.0_dp*epsilon(0.0_dp)
839
840 INTEGER :: dx, dy, dz, handle, icontact, ix, iy, &
841 iz, lx, ly, lz, ncontacts, ux, uy, uz
842 REAL(kind=dp) :: dvol, pot, proj, v1, v2
843 REAL(kind=dp), DIMENSION(3) :: dirvector_bias, point_coord, &
844 point_indices, vector
845
846 CALL timeset(routinen, handle)
847
848 ncontacts = SIZE(contact_env)
849 cpassert(SIZE(contact_control) == ncontacts)
850 cpassert(ncontacts == 2)
851
852 dirvector_bias = contact_env(2)%origin_bias - contact_env(1)%origin_bias
853 v1 = contact_control(1)%v_external
854 v2 = contact_control(2)%v_external
855
856 lx = v_hartree%pw_grid%bounds_local(1, 1)
857 ux = v_hartree%pw_grid%bounds_local(2, 1)
858 ly = v_hartree%pw_grid%bounds_local(1, 2)
859 uy = v_hartree%pw_grid%bounds_local(2, 2)
860 lz = v_hartree%pw_grid%bounds_local(1, 3)
861 uz = v_hartree%pw_grid%bounds_local(2, 3)
862
863 dx = v_hartree%pw_grid%npts(1)/2
864 dy = v_hartree%pw_grid%npts(2)/2
865 dz = v_hartree%pw_grid%npts(3)/2
866
867 dvol = v_hartree%pw_grid%dvol
868
869 DO iz = lz, uz
870 point_indices(3) = real(iz + dz, kind=dp)
871 DO iy = ly, uy
872 point_indices(2) = real(iy + dy, kind=dp)
873
874 DO ix = lx, ux
875 point_indices(1) = real(ix + dx, kind=dp)
876 point_coord(:) = matmul(v_hartree%pw_grid%dh, point_indices)
877
878 vector = point_coord - contact_env(1)%origin_bias
879 proj = projection_on_direction_vector(vector, dirvector_bias)
880 IF (proj + threshold >= 0.0_dp .AND. proj - threshold <= 1.0_dp) THEN
881 ! scattering region
882 ! proj == 0 we are at the first contact boundary
883 ! proj == 1 we are at the second contact boundary
884 IF (proj < 0.0_dp) THEN
885 proj = 0.0_dp
886 ELSE IF (proj > 1.0_dp) THEN
887 proj = 1.0_dp
888 END IF
889 pot = v1 + (v2 - v1)*proj
890 ELSE
891 pot = 0.0_dp
892 DO icontact = 1, ncontacts
893 vector = point_coord - contact_env(icontact)%origin_bias
894 proj = projection_on_direction_vector(vector, contact_env(icontact)%direction_vector_bias)
895
896 IF (proj + threshold >= 0.0_dp .AND. proj - threshold <= 1.0_dp) THEN
897 pot = contact_control(icontact)%v_external
898 EXIT
899 END IF
900 END DO
901 END IF
902
903 v_hartree%array(ix, iy, iz) = pot*dvol
904 END DO
905 END DO
906 END DO
907
908 CALL timestop(handle)
909 END SUBROUTINE negf_env_init_v_hartree
910
911! **************************************************************************************************
912!> \brief Detect the axis towards secondary unit cell.
913!> \param direction_vector direction vector
914!> \param subsys_contact QuickStep subsystem of the contact force environment
915!> \param eps_geometry accuracy in mapping atoms between different force environments
916!> \return direction axis: 0 (undefined), 1 (x), 2(y), 3 (z)
917!> \par History
918!> * 08.2017 created [Sergey Chulkov]
919! **************************************************************************************************
920 FUNCTION contact_direction_axis(direction_vector, subsys_contact, eps_geometry) RESULT(direction_axis)
921 REAL(kind=dp), DIMENSION(3), INTENT(in) :: direction_vector
922 TYPE(qs_subsys_type), POINTER :: subsys_contact
923 REAL(kind=dp), INTENT(in) :: eps_geometry
924 INTEGER :: direction_axis
925
926 INTEGER :: i, naxes
927 REAL(kind=dp), DIMENSION(3) :: scaled
928 TYPE(cell_type), POINTER :: cell
929
930 CALL qs_subsys_get(subsys_contact, cell=cell)
931 CALL real_to_scaled(scaled, direction_vector, cell)
932
933 naxes = 0
934 direction_axis = 0 ! initialize to make GCC<=6 happy
935
936 DO i = 1, 3
937 IF (abs(scaled(i)) > eps_geometry) THEN
938 IF (scaled(i) > 0.0_dp) THEN
939 direction_axis = i
940 ELSE
941 direction_axis = -i
942 END IF
943 naxes = naxes + 1
944 END IF
945 END DO
946
947 ! direction_vector is not parallel to one of the unit cell's axis
948 IF (naxes /= 1) direction_axis = 0
949 END FUNCTION contact_direction_axis
950
951! **************************************************************************************************
952!> \brief Estimate energy of the highest spin-alpha occupied molecular orbital.
953!> \param homo_energy HOMO energy (initialised on exit)
954!> \param qs_env QuickStep environment
955!> \par History
956!> * 01.2017 created [Sergey Chulkov]
957! **************************************************************************************************
958 SUBROUTINE negf_homo_energy_estimate(homo_energy, qs_env)
959 REAL(kind=dp), INTENT(out) :: homo_energy
960 TYPE(qs_environment_type), POINTER :: qs_env
961
962 CHARACTER(LEN=*), PARAMETER :: routinen = 'negf_homo_energy_estimate'
963 INTEGER, PARAMETER :: gamma_point = 1
964
965 INTEGER :: handle, homo, ikpgr, ikpoint, imo, &
966 ispin, kplocal, nmo, nspins
967 INTEGER, DIMENSION(2) :: kp_range
968 LOGICAL :: do_kpoints
969 REAL(kind=dp) :: my_homo_energy
970 REAL(kind=dp), DIMENSION(:), POINTER :: eigenvalues
971 TYPE(kpoint_env_p_type), DIMENSION(:), POINTER :: kp_env
972 TYPE(kpoint_type), POINTER :: kpoints
973 TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
974 TYPE(mo_set_type), DIMENSION(:, :), POINTER :: mos_kp
975 TYPE(mp_para_env_type), POINTER :: para_env, para_env_kp
976
977 CALL timeset(routinen, handle)
978 my_homo_energy = 0.0_dp
979
980 CALL get_qs_env(qs_env, para_env=para_env, mos=mos, kpoints=kpoints, do_kpoints=do_kpoints)
981
982 IF (do_kpoints) THEN
983 CALL get_kpoint_info(kpoints, kp_env=kp_env, kp_range=kp_range, para_env_kp=para_env_kp)
984
985 ! looking for a processor that holds the gamma point
986 IF (para_env_kp%mepos == 0 .AND. kp_range(1) <= gamma_point .AND. kp_range(2) >= gamma_point) THEN
987 kplocal = kp_range(2) - kp_range(1) + 1
988
989 DO ikpgr = 1, kplocal
990 CALL get_kpoint_env(kp_env(ikpgr)%kpoint_env, nkpoint=ikpoint, mos=mos_kp)
991
992 IF (ikpoint == gamma_point) THEN
993 ! mos_kp(component, spin), where component = 1 (real), or 2 (imaginary)
994 CALL get_mo_set(mos_kp(1, 1), homo=homo, eigenvalues=eigenvalues) ! mu=fermi_level
995
996 my_homo_energy = eigenvalues(homo)
997 EXIT
998 END IF
999 END DO
1000 END IF
1001
1002 CALL para_env%sum(my_homo_energy)
1003 ELSE
1004 ! Hamiltonian of the bulk contact region has been computed without k-points.
1005 ! Try to obtain the HOMO energy assuming there is no OT. We probably should abort here
1006 ! as we do need a second replica of the bulk contact unit cell along transport
1007 ! direction anyway which is not available without k-points.
1008
1009 cpabort("It is strongly advised to use k-points within all contact FORCE_EVAL-s")
1010
1011 nspins = SIZE(mos)
1012
1013 spin_loop: DO ispin = 1, nspins
1014 CALL get_mo_set(mos(ispin), homo=homo, nmo=nmo, eigenvalues=eigenvalues)
1015
1016 DO imo = nmo, 1, -1
1017 IF (eigenvalues(imo) /= 0.0_dp) EXIT spin_loop
1018 END DO
1019 END DO spin_loop
1020
1021 IF (imo == 0) THEN
1022 cpabort("Orbital transformation (OT) for contact FORCE_EVAL-s is not supported")
1023 END IF
1024
1025 my_homo_energy = eigenvalues(homo)
1026 END IF
1027
1028 homo_energy = my_homo_energy
1029 CALL timestop(handle)
1030 END SUBROUTINE negf_homo_energy_estimate
1031
1032! **************************************************************************************************
1033!> \brief List atoms from the contact's primary unit cell.
1034!> \param atomlist_cell0 list of atoms belonging to the contact's primary unit cell
1035!> (allocate and initialised on exit)
1036!> \param atom_map_cell0 atomic map of atoms from 'atomlist_cell0' (allocate and initialised on exit)
1037!> \param atomlist_bulk list of atoms belonging to the bulk contact region
1038!> \param atom_map atomic map of atoms from 'atomlist_bulk'
1039!> \param origin origin of the contact
1040!> \param direction_vector direction vector of the contact
1041!> \param direction_axis axis towards secondary unit cell
1042!> \param subsys_device QuickStep subsystem of the device force environment
1043!> \par History
1044!> * 08.2017 created [Sergey Chulkov]
1045! **************************************************************************************************
1046 SUBROUTINE list_atoms_in_bulk_primary_unit_cell(atomlist_cell0, atom_map_cell0, atomlist_bulk, atom_map, &
1047 origin, direction_vector, direction_axis, subsys_device)
1048 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(inout) :: atomlist_cell0
1049 TYPE(negf_atom_map_type), ALLOCATABLE, &
1050 DIMENSION(:), INTENT(inout) :: atom_map_cell0
1051 INTEGER, DIMENSION(:), INTENT(in) :: atomlist_bulk
1052 TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
1053 REAL(kind=dp), DIMENSION(3), INTENT(in) :: origin, direction_vector
1054 INTEGER, INTENT(in) :: direction_axis
1055 TYPE(qs_subsys_type), POINTER :: subsys_device
1056
1057 CHARACTER(LEN=*), PARAMETER :: routinen = 'list_atoms_in_bulk_primary_unit_cell'
1058
1059 INTEGER :: atom_min, dir_axis_min, &
1060 direction_axis_abs, handle, iatom, &
1061 natoms_bulk, natoms_cell0
1062 REAL(kind=dp) :: proj, proj_min
1063 REAL(kind=dp), DIMENSION(3) :: vector
1064 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1065
1066 CALL timeset(routinen, handle)
1067 CALL qs_subsys_get(subsys_device, particle_set=particle_set)
1068
1069 natoms_bulk = SIZE(atomlist_bulk)
1070 cpassert(SIZE(atom_map, 1) == natoms_bulk)
1071 direction_axis_abs = abs(direction_axis)
1072
1073 ! looking for the nearest atom from the scattering region
1074 proj_min = 1.0_dp
1075 atom_min = 1
1076 DO iatom = 1, natoms_bulk
1077 vector = particle_set(atomlist_bulk(iatom))%r - origin
1078 proj = projection_on_direction_vector(vector, direction_vector)
1079
1080 IF (proj < proj_min) THEN
1081 proj_min = proj
1082 atom_min = iatom
1083 END IF
1084 END DO
1085
1086 dir_axis_min = atom_map(atom_min)%cell(direction_axis_abs)
1087
1088 natoms_cell0 = 0
1089 DO iatom = 1, natoms_bulk
1090 IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min) &
1091 natoms_cell0 = natoms_cell0 + 1
1092 END DO
1093
1094 ALLOCATE (atomlist_cell0(natoms_cell0))
1095 ALLOCATE (atom_map_cell0(natoms_cell0))
1096
1097 natoms_cell0 = 0
1098 DO iatom = 1, natoms_bulk
1099 IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min) THEN
1100 natoms_cell0 = natoms_cell0 + 1
1101 atomlist_cell0(natoms_cell0) = atomlist_bulk(iatom)
1102 atom_map_cell0(natoms_cell0) = atom_map(iatom)
1103 END IF
1104 END DO
1105
1106 CALL timestop(handle)
1107 END SUBROUTINE list_atoms_in_bulk_primary_unit_cell
1108
1109! **************************************************************************************************
1110!> \brief List atoms from the contact's secondary unit cell.
1111!> \param atomlist_cell1 list of atoms belonging to the contact's secondary unit cell
1112!> (allocate and initialised on exit)
1113!> \param atom_map_cell1 atomic map of atoms from 'atomlist_cell1'
1114!> (allocate and initialised on exit)
1115!> \param atomlist_bulk list of atoms belonging to the bulk contact region
1116!> \param atom_map atomic map of atoms from 'atomlist_bulk'
1117!> \param origin origin of the contact
1118!> \param direction_vector direction vector of the contact
1119!> \param direction_axis axis towards the secondary unit cell
1120!> \param subsys_device QuickStep subsystem of the device force environment
1121!> \par History
1122!> * 11.2017 created [Sergey Chulkov]
1123!> \note Cloned from list_atoms_in_bulk_primary_unit_cell. Will be removed once we can managed to
1124!> maintain consistency between real-space matrices from different force_eval sections.
1125! **************************************************************************************************
1126 SUBROUTINE list_atoms_in_bulk_secondary_unit_cell(atomlist_cell1, atom_map_cell1, atomlist_bulk, atom_map, &
1127 origin, direction_vector, direction_axis, subsys_device)
1128 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(inout) :: atomlist_cell1
1129 TYPE(negf_atom_map_type), ALLOCATABLE, &
1130 DIMENSION(:), INTENT(inout) :: atom_map_cell1
1131 INTEGER, DIMENSION(:), INTENT(in) :: atomlist_bulk
1132 TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
1133 REAL(kind=dp), DIMENSION(3), INTENT(in) :: origin, direction_vector
1134 INTEGER, INTENT(in) :: direction_axis
1135 TYPE(qs_subsys_type), POINTER :: subsys_device
1136
1137 CHARACTER(LEN=*), PARAMETER :: routinen = 'list_atoms_in_bulk_secondary_unit_cell'
1138
1139 INTEGER :: atom_min, dir_axis_min, &
1140 direction_axis_abs, handle, iatom, &
1141 natoms_bulk, natoms_cell1, offset
1142 REAL(kind=dp) :: proj, proj_min
1143 REAL(kind=dp), DIMENSION(3) :: vector
1144 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1145
1146 CALL timeset(routinen, handle)
1147 CALL qs_subsys_get(subsys_device, particle_set=particle_set)
1148
1149 natoms_bulk = SIZE(atomlist_bulk)
1150 cpassert(SIZE(atom_map, 1) == natoms_bulk)
1151 direction_axis_abs = abs(direction_axis)
1152 offset = sign(1, direction_axis)
1153
1154 ! looking for the nearest atom from the scattering region
1155 proj_min = 1.0_dp
1156 atom_min = 1
1157 DO iatom = 1, natoms_bulk
1158 vector = particle_set(atomlist_bulk(iatom))%r - origin
1159 proj = projection_on_direction_vector(vector, direction_vector)
1160
1161 IF (proj < proj_min) THEN
1162 proj_min = proj
1163 atom_min = iatom
1164 END IF
1165 END DO
1166
1167 dir_axis_min = atom_map(atom_min)%cell(direction_axis_abs)
1168
1169 natoms_cell1 = 0
1170 DO iatom = 1, natoms_bulk
1171 IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min + offset) &
1172 natoms_cell1 = natoms_cell1 + 1
1173 END DO
1174
1175 ALLOCATE (atomlist_cell1(natoms_cell1))
1176 ALLOCATE (atom_map_cell1(natoms_cell1))
1177
1178 natoms_cell1 = 0
1179 DO iatom = 1, natoms_bulk
1180 IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min + offset) THEN
1181 natoms_cell1 = natoms_cell1 + 1
1182 atomlist_cell1(natoms_cell1) = atomlist_bulk(iatom)
1183 atom_map_cell1(natoms_cell1) = atom_map(iatom)
1184 atom_map_cell1(natoms_cell1)%cell(direction_axis_abs) = dir_axis_min
1185 END IF
1186 END DO
1187
1188 CALL timestop(handle)
1189 END SUBROUTINE list_atoms_in_bulk_secondary_unit_cell
1190
1191! **************************************************************************************************
1192!> \brief Release a NEGF environment variable.
1193!> \param negf_env NEGF environment to release
1194!> \par History
1195!> * 01.2017 created [Sergey Chulkov]
1196! **************************************************************************************************
1197 SUBROUTINE negf_env_release(negf_env)
1198 TYPE(negf_env_type), INTENT(inout) :: negf_env
1199
1200 CHARACTER(len=*), PARAMETER :: routinen = 'negf_env_release'
1201
1202 INTEGER :: handle, icontact
1203
1204 CALL timeset(routinen, handle)
1205
1206 IF (ALLOCATED(negf_env%contacts)) THEN
1207 DO icontact = SIZE(negf_env%contacts), 1, -1
1208 CALL negf_env_contact_release(negf_env%contacts(icontact))
1209 END DO
1210
1211 DEALLOCATE (negf_env%contacts)
1212 END IF
1213
1214 ! h_s
1215 CALL cp_fm_release(negf_env%h_s)
1216
1217 ! h_sc
1218 CALL cp_fm_release(negf_env%h_sc)
1219
1220 ! s_s
1221 IF (ASSOCIATED(negf_env%s_s)) THEN
1222 CALL cp_fm_release(negf_env%s_s)
1223 DEALLOCATE (negf_env%s_s)
1224 NULLIFY (negf_env%s_s)
1225 END IF
1226
1227 ! s_sc
1228 CALL cp_fm_release(negf_env%s_sc)
1229
1230 ! v_hartree_s
1231 IF (ASSOCIATED(negf_env%v_hartree_s)) THEN
1232 CALL cp_fm_release(negf_env%v_hartree_s)
1233 DEALLOCATE (negf_env%v_hartree_s)
1234 NULLIFY (negf_env%v_hartree_s)
1235 END IF
1236
1237 ! density mixing
1238 IF (ASSOCIATED(negf_env%mixing_storage)) THEN
1239 CALL mixing_storage_release(negf_env%mixing_storage)
1240 DEALLOCATE (negf_env%mixing_storage)
1241 END IF
1242
1243 CALL timestop(handle)
1244 END SUBROUTINE negf_env_release
1245
1246! **************************************************************************************************
1247!> \brief Release a NEGF contact environment variable.
1248!> \param contact_env NEGF contact environment to release
1249! **************************************************************************************************
1250 SUBROUTINE negf_env_contact_release(contact_env)
1251 TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
1252
1253 CHARACTER(len=*), PARAMETER :: routinen = 'negf_env_contact_release'
1254
1255 INTEGER :: handle
1256
1257 CALL timeset(routinen, handle)
1258
1259 ! h_00
1260 CALL cp_fm_release(contact_env%h_00)
1261
1262 ! h_01
1263 CALL cp_fm_release(contact_env%h_01)
1264
1265 ! rho_00
1266 CALL cp_fm_release(contact_env%rho_00)
1267
1268 ! rho_01
1269 CALL cp_fm_release(contact_env%rho_01)
1270
1271 ! s_00
1272 IF (ASSOCIATED(contact_env%s_00)) THEN
1273 CALL cp_fm_release(contact_env%s_00)
1274 DEALLOCATE (contact_env%s_00)
1275 NULLIFY (contact_env%s_00)
1276 END IF
1277
1278 ! s_01
1279 IF (ASSOCIATED(contact_env%s_01)) THEN
1280 CALL cp_fm_release(contact_env%s_01)
1281 DEALLOCATE (contact_env%s_01)
1282 NULLIFY (contact_env%s_01)
1283 END IF
1284
1285 IF (ALLOCATED(contact_env%atomlist_cell0)) DEALLOCATE (contact_env%atomlist_cell0)
1286 IF (ALLOCATED(contact_env%atomlist_cell1)) DEALLOCATE (contact_env%atomlist_cell1)
1287 IF (ALLOCATED(contact_env%atom_map_cell0)) DEALLOCATE (contact_env%atom_map_cell0)
1288
1289 CALL timestop(handle)
1290 END SUBROUTINE negf_env_contact_release
1291END MODULE negf_env_types
Handles all functions related to the CELL.
Definition cell_types.F:15
subroutine, public real_to_scaled(s, r, cell)
Transform real to scaled cell coordinates. s=h_inv*r.
Definition cell_types.F:491
methods related to the blacs parallel environment
Defines control structures, which contain the parameters and the settings for the DFT-based calculati...
subroutine, public dbcsr_deallocate_matrix(matrix)
...
subroutine, public dbcsr_copy(matrix_b, matrix_a, name, keep_sparsity, keep_imaginary)
...
subroutine, public dbcsr_init_p(matrix)
...
subroutine, public dbcsr_set(matrix, alpha)
...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_create(matrix, matrix_struct, name, use_sp, nrow, ncol, set_zero)
creates a new full matrix with the given structure
Interface for the force calculations.
recursive subroutine, public force_env_get(force_env, in_use, fist_env, qs_env, meta_env, fp_env, subsys, para_env, potential_energy, additional_potential, kinetic_energy, harmonic_shell, kinetic_shell, cell, sub_force_env, qmmm_env, qmmmx_env, eip_env, pwdft_env, globenv, input, force_env_section, method_name_id, root_section, mixed_env, nnp_env, embed_env, ipi_env)
returns various attributes about the force environment
integer, parameter, public use_qs_force
objects that represent the structure of input sections and the data contained in an input section
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
Types and basic routines needed for a kpoint calculation.
subroutine, public get_kpoint_env(kpoint_env, nkpoint, wkp, xkp, is_local, mos)
Get information from a single kpoint environment.
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.
Map atoms between various force environments.
subroutine, public negf_map_atomic_indices(atom_map, atom_list, subsys_device, subsys_contact, eps_geometry)
Map atoms in the cell 'subsys_device' listed in 'atom_list' with the corresponding atoms in the cell ...
Input control types for NEGF based quantum transport calculations.
Environment for NEGF based quantum transport calculations.
subroutine, public negf_env_release(negf_env)
Release a NEGF environment variable.
subroutine, public negf_env_create(negf_env, sub_env, negf_control, force_env, negf_mixing_section, log_unit)
Create a new NEGF environment and compute the relevant Kohn-Sham matrices.
Helper routines to manipulate with matrices.
integer function, public number_of_atomic_orbitals(subsys, atom_list)
Compute the number of atomic orbitals of the given set of atoms.
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_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.
Environment for NEGF based quantum transport calculations.
Routines to deal with vectors in 3-D real space.
pure real(kind=dp) function, public projection_on_direction_vector(vector, vector0)
project the 'vector' onto the direction 'vector0'. Both vectors should have the same origin.
subroutine, public contact_direction_vector(origin, direction_vector, origin_bias, direction_vector_bias, atomlist_screening, atomlist_bulk, subsys)
compute direction vector of the given contact
Define the data structure for the particle information.
container for various plainwaves related things
subroutine, public pw_env_get(pw_env, pw_pools, cube_info, gridlevel_info, auxbas_pw_pool, auxbas_grid, auxbas_rs_desc, auxbas_rs_grid, rs_descs, rs_grids, xc_pw_pool, vdw_pw_pool, poisson_env, interp_section)
returns the various attributes of the pw env
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
module that contains the definitions of the scf types
subroutine, public mixing_storage_release(mixing_store)
releases a mixing_storage
subroutine, public mixing_storage_create(mixing_store, mixing_section, mixing_method, ecut)
creates a mixing_storage
Utility subroutine for qs energy calculation.
subroutine, public qs_energies_init(qs_env, calc_forces)
Refactoring of qs_energies_scf. Driver routine for the initial setup and calculations for a qs energy...
Perform a QUICKSTEP wavefunction optimization (single point)
Definition qs_energy.F:14
subroutine, public qs_energies(qs_env, consistent_energies, calc_forces)
Driver routine for QUICKSTEP single point wavefunction optimization.
Definition qs_energy.F:70
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, sab_cneo, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_ri_aux_kp, matrix_s, matrix_s_ri_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, rhoz_cneo_set, ecoul_1c, rho0_s_rs, rho0_s_gs, rhoz_cneo_s_rs, rhoz_cneo_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, harris_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, wanniercentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, eeq, rhs, do_rixs, tb_tblite)
Get the QUICKSTEP environment.
Integrate single or product functions over a potential on a RS grid.
Definition and initialisation of the mo data type.
Definition qs_mo_types.F:22
subroutine, public get_mo_set(mo_set, maxocc, homo, lfomo, nao, nelectron, n_el_f, nmo, eigenvalues, occupation_numbers, mo_coeff, mo_coeff_b, uniform_occupation, kts, mu, flexible_electron_count)
Get the components of a MO set data structure.
superstucture that hold various representations of the density and keeps track of which ones are vali...
subroutine, public qs_rho_get(rho_struct, rho_ao, rho_ao_im, rho_ao_kp, rho_ao_im_kp, rho_r, drho_r, rho_g, drho_g, tau_r, tau_g, rho_r_valid, drho_r_valid, rho_g_valid, drho_g_valid, tau_r_valid, tau_g_valid, tot_rho_r, tot_rho_g, rho_r_sccs, soft_valid, complex_rho_ao)
returns info about the density described by this object. If some representation is not available an e...
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)
...
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
represent a full matrix
allows for the creation of an array of force_env
wrapper to abstract the force evaluation of the various methods
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...
Input parameters related to a single contact.
Input parameters related to the NEGF run.
Contact-specific NEGF environment.
contained for different pw related things
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
keeps the density in various representations, keeping track of which ones are valid.