Line data Source code
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 Environment for NEGF based quantum transport calculations
10 : ! **************************************************************************************************
11 : MODULE negf_env_types
12 : USE cell_types, ONLY: cell_type,&
13 : real_to_scaled
14 : USE cp_blacs_env, ONLY: cp_blacs_env_type
15 : USE cp_control_types, ONLY: dft_control_type
16 : USE cp_dbcsr_api, ONLY: dbcsr_copy,&
17 : dbcsr_deallocate_matrix,&
18 : dbcsr_init_p,&
19 : dbcsr_p_type,&
20 : dbcsr_set
21 : USE cp_files, ONLY: close_file,&
22 : open_file
23 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
24 : cp_fm_struct_release,&
25 : cp_fm_struct_type
26 : USE cp_fm_types, ONLY: cp_fm_create,&
27 : cp_fm_get_info,&
28 : cp_fm_get_submatrix,&
29 : cp_fm_release,&
30 : cp_fm_set_submatrix,&
31 : cp_fm_type
32 : USE cp_log_handling, ONLY: cp_get_default_logger,&
33 : cp_logger_type
34 : USE force_env_types, ONLY: force_env_get,&
35 : force_env_p_type,&
36 : force_env_type,&
37 : use_qs_force
38 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
39 : section_vals_type,&
40 : section_vals_val_get
41 : USE kinds, ONLY: default_path_length,&
42 : default_string_length,&
43 : dp
44 : USE kpoint_types, ONLY: get_kpoint_env,&
45 : get_kpoint_info,&
46 : kpoint_env_p_type,&
47 : kpoint_type
48 : USE message_passing, ONLY: mp_para_env_type
49 : USE negf_atom_map, ONLY: negf_atom_map_type,&
50 : negf_map_atomic_indices
51 : USE negf_control_types, ONLY: negf_control_contact_type,&
52 : negf_control_type
53 : USE negf_io, ONLY: negf_print_matrix_to_file,&
54 : negf_read_matrix_from_file,&
55 : negf_restart_file_name
56 : USE negf_matrix_utils, ONLY: invert_cell_to_index,&
57 : negf_copy_contact_matrix,&
58 : negf_copy_sym_dbcsr_to_fm_submat,&
59 : number_of_atomic_orbitals
60 : USE negf_subgroup_types, ONLY: negf_subgroup_env_type
61 : USE negf_vectors, ONLY: contact_direction_vector,&
62 : projection_on_direction_vector
63 : USE particle_types, ONLY: particle_type
64 : USE pw_env_types, ONLY: pw_env_get,&
65 : pw_env_type
66 : USE pw_pool_types, ONLY: pw_pool_type
67 : USE pw_types, ONLY: pw_r3d_rs_type
68 : USE qs_density_mixing_types, ONLY: mixing_storage_create,&
69 : mixing_storage_release,&
70 : mixing_storage_type
71 : USE qs_energy, ONLY: qs_energies
72 : USE qs_energy_init, ONLY: qs_energies_init
73 : USE qs_environment_types, ONLY: get_qs_env,&
74 : qs_environment_type
75 : USE qs_integrate_potential, ONLY: integrate_v_rspace
76 : USE qs_mo_types, ONLY: get_mo_set,&
77 : mo_set_type
78 : USE qs_rho_types, ONLY: qs_rho_get,&
79 : qs_rho_type
80 : USE qs_scf_post_tb, ONLY: rebuild_pw_env
81 : USE qs_subsys_types, ONLY: qs_subsys_get,&
82 : qs_subsys_type
83 : #include "./base/base_uses.f90"
84 :
85 : IMPLICIT NONE
86 : PRIVATE
87 :
88 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_env_types'
89 : LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .TRUE.
90 :
91 : PUBLIC :: negf_env_type, negf_env_contact_type
92 : PUBLIC :: negf_env_create, negf_env_release
93 :
94 : ! **************************************************************************************************
95 : !> \brief Contact-specific NEGF environment.
96 : !> \author Sergey Chulkov
97 : ! **************************************************************************************************
98 : TYPE negf_env_contact_type
99 : REAL(kind=dp), DIMENSION(3) :: direction_vector = -1.0_dp, origin = -1.0_dp
100 : REAL(kind=dp), DIMENSION(3) :: direction_vector_bias = -1.0_dp, origin_bias = -1.0_dp
101 : !> an axis towards the secondary contact unit cell which coincides with the transport direction
102 : !> 0 (undefined), 1 (+x), 2 (+y), 3 (+z), -1 (-x), -2 (-y), -3 (-z)
103 : INTEGER :: direction_axis = -1
104 : !> atoms belonging to a primary contact unit cell
105 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atomlist_cell0
106 : !> atoms belonging to a secondary contact unit cell (will be removed one day ...)
107 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atomlist_cell1
108 : !> list of equivalent atoms in an appropriate contact force environment
109 : TYPE(negf_atom_map_type), ALLOCATABLE, &
110 : DIMENSION(:) :: atom_map_cell0, atom_map_cell1
111 : !> Fermi energy
112 : REAL(kind=dp) :: fermi_energy = 0.0_dp
113 : !> energy of the HOMO
114 : REAL(kind=dp) :: homo_energy = -1.0_dp
115 : !> number of electrons Sp(rho_00,s_00)
116 : REAL(kind=dp) :: nelectrons_qs_cell0 = 0.0_dp
117 : !> number of electrons Sp(rho_01,s_01)
118 : REAL(kind=dp) :: nelectrons_qs_cell1 = 0.0_dp
119 : !> diagonal (h_00) and off-diagonal (h_01) blocks of the contact Kohn-Sham matrix ([number_of_spins]).
120 : !> The matrix h_01 is of the shape [nao_cell0 x nao_cell1]
121 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: h_00, h_01
122 : !> diagonal and off-diagonal blocks of the density matrix
123 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: rho_00, rho_01
124 : !> diagonal and off-diagonal blocks of the overlap matrix
125 : TYPE(cp_fm_type), POINTER :: s_00 => null(), s_01 => null()
126 : END TYPE negf_env_contact_type
127 :
128 : ! **************************************************************************************************
129 : !> \brief NEGF environment.
130 : !> \author Sergey Chulkov
131 : ! **************************************************************************************************
132 : TYPE negf_env_type
133 : !> contact-specific NEGF environments
134 : TYPE(negf_env_contact_type), ALLOCATABLE, &
135 : DIMENSION(:) :: contacts
136 : !> Kohn-Sham matrix of the scattering region
137 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: h_s
138 : !> Kohn-Sham matrix of the scattering region -- contact interface ([nspins, ncontacts])
139 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :) :: h_sc
140 : !> overlap matrix of the scattering region
141 : TYPE(cp_fm_type), POINTER :: s_s => null()
142 : !> an external Hartree potential in atomic basis set representation
143 : TYPE(cp_fm_type), POINTER :: v_hartree_s => null()
144 : !> overlap matrix of the scattering region -- contact interface for every contact ([ncontacts])
145 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: s_sc
146 : !> structure needed for density mixing
147 : TYPE(mixing_storage_type), POINTER :: mixing_storage => NULL()
148 : !> density mixing method
149 : INTEGER :: mixing_method = -1
150 : !> number of electrons Sp(rho_s,s_s)
151 : REAL(kind=dp) :: nelectrons_ref = 0.0_dp
152 : !> number of electrons Sp(rho_s,s_s)
153 : REAL(kind=dp) :: nelectrons = 0.0_dp
154 : END TYPE negf_env_type
155 :
156 : ! **************************************************************************************************
157 : !> \brief Allocatable list of the type 'negf_atom_map_type'.
158 : !> \author Sergey Chulkov
159 : ! **************************************************************************************************
160 : TYPE negf_atom_map_contact_type
161 : TYPE(negf_atom_map_type), ALLOCATABLE, DIMENSION(:) :: atom_map
162 : END TYPE negf_atom_map_contact_type
163 :
164 : CONTAINS
165 :
166 : ! **************************************************************************************************
167 : !> \brief Create a new NEGF environment and compute the relevant Kohn-Sham matrices.
168 : !> \param negf_env NEGF environment to create
169 : !> \param sub_env NEGF parallel (sub)group environment
170 : !> \param negf_control NEGF control
171 : !> \param force_env the primary force environment
172 : !> \param negf_mixing_section pointer to a mixing section within the NEGF input section
173 : !> \param log_unit output unit number
174 : !> \par History
175 : !> * 01.2017 created [Sergey Chulkov]
176 : ! **************************************************************************************************
177 6 : SUBROUTINE negf_env_create(negf_env, sub_env, negf_control, force_env, negf_mixing_section, log_unit)
178 : TYPE(negf_env_type), INTENT(inout) :: negf_env
179 : TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
180 : TYPE(negf_control_type), POINTER :: negf_control
181 : TYPE(force_env_type), POINTER :: force_env
182 : TYPE(section_vals_type), POINTER :: negf_mixing_section
183 : INTEGER, INTENT(in) :: log_unit
184 :
185 : CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_create'
186 :
187 : CHARACTER(len=default_string_length) :: contact_str, force_env_str, &
188 : n_force_env_str
189 : INTEGER :: handle, icontact, in_use, n_force_env, &
190 : ncontacts
191 : LOGICAL :: do_kpoints, is_dft_entire
192 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
193 6 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp
194 : TYPE(dft_control_type), POINTER :: dft_control
195 6 : TYPE(force_env_p_type), DIMENSION(:), POINTER :: sub_force_env
196 : TYPE(mp_para_env_type), POINTER :: para_env
197 : TYPE(negf_atom_map_contact_type), ALLOCATABLE, &
198 6 : DIMENSION(:) :: map_contact
199 : TYPE(pw_r3d_rs_type), POINTER :: v_hartree_rspace
200 : TYPE(qs_environment_type), POINTER :: qs_env, qs_env_contact
201 : TYPE(qs_subsys_type), POINTER :: subsys, subsys_contact
202 : TYPE(section_vals_type), POINTER :: negf_section, root_section
203 :
204 6 : CALL timeset(routineN, handle)
205 :
206 : ! ensure we have Quickstep enabled for all force_env
207 6 : NULLIFY (sub_force_env)
208 : CALL force_env_get(force_env, in_use=in_use, qs_env=qs_env, root_section=root_section, &
209 6 : sub_force_env=sub_force_env)
210 :
211 6 : IF (ASSOCIATED(sub_force_env)) THEN
212 2 : n_force_env = SIZE(sub_force_env)
213 : ELSE
214 4 : n_force_env = 0
215 : END IF
216 :
217 6 : IF (in_use == use_qs_force) THEN
218 10 : DO icontact = 1, n_force_env
219 4 : CALL force_env_get(sub_force_env(icontact)%force_env, in_use=in_use)
220 10 : IF (in_use /= use_qs_force) EXIT
221 : END DO
222 : END IF
223 :
224 6 : IF (in_use /= use_qs_force) THEN
225 0 : CPABORT("Quickstep is required for NEGF run.")
226 : END IF
227 :
228 : ! check that all mentioned FORCE_EVAL sections are actually present
229 6 : ncontacts = SIZE(negf_control%contacts)
230 :
231 18 : DO icontact = 1, ncontacts
232 18 : IF (negf_control%contacts(icontact)%force_env_index > n_force_env) THEN
233 0 : WRITE (contact_str, '(I11)') icontact
234 0 : WRITE (force_env_str, '(I11)') negf_control%contacts(icontact)%force_env_index
235 0 : WRITE (n_force_env_str, '(I11)') n_force_env
236 :
237 : CALL cp_abort(__LOCATION__, &
238 : "Contact number "//TRIM(ADJUSTL(contact_str))//" is linked with the FORCE_EVAL section number "// &
239 : TRIM(ADJUSTL(force_env_str))//", however only "//TRIM(ADJUSTL(n_force_env_str))// &
240 : " FORCE_EVAL sections have been found. Note that FORCE_EVAL sections are enumerated from 0"// &
241 0 : " and that the primary (0-th) section must contain all the atoms.")
242 : END IF
243 : END DO
244 :
245 : ! create basic matrices and neighbour lists for the primary force_env,
246 : ! so we know how matrix elements are actually distributed across CPUs.
247 6 : CALL qs_energies_init(qs_env, calc_forces=.FALSE.)
248 : CALL get_qs_env(qs_env, blacs_env=blacs_env, do_kpoints=do_kpoints, &
249 : matrix_s_kp=matrix_s_kp, matrix_ks_kp=matrix_ks_kp, &
250 6 : para_env=para_env, subsys=subsys, v_hartree_rspace=v_hartree_rspace)
251 :
252 6 : negf_section => section_vals_get_subs_vals(root_section, "NEGF")
253 :
254 6 : IF (do_kpoints) THEN
255 0 : CPABORT("k-points are currently not supported for device FORCE_EVAL")
256 : END IF
257 :
258 : ! stage 1: map the atoms between the device force_env and all contact force_env-s
259 120 : ALLOCATE (negf_env%contacts(ncontacts))
260 30 : ALLOCATE (map_contact(ncontacts))
261 :
262 18 : DO icontact = 1, ncontacts
263 18 : IF (negf_control%contacts(icontact)%force_env_index > 0) THEN
264 4 : CALL force_env_get(sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, qs_env=qs_env_contact)
265 4 : CALL get_qs_env(qs_env_contact, subsys=subsys_contact)
266 :
267 : CALL negf_env_contact_init_maps(contact_env=negf_env%contacts(icontact), &
268 : contact_control=negf_control%contacts(icontact), &
269 : atom_map=map_contact(icontact)%atom_map, &
270 : eps_geometry=negf_control%eps_geometry, &
271 : subsys_device=subsys, &
272 4 : subsys_contact=subsys_contact)
273 :
274 4 : IF (negf_env%contacts(icontact)%direction_axis == 0) THEN
275 0 : WRITE (contact_str, '(I11)') icontact
276 0 : WRITE (force_env_str, '(I11)') negf_control%contacts(icontact)%force_env_index
277 : CALL cp_abort(__LOCATION__, &
278 : "One lattice vector of the contact unit cell (FORCE_EVAL section "// &
279 : TRIM(ADJUSTL(force_env_str))//") must be parallel to the direction of the contact "// &
280 0 : TRIM(ADJUSTL(contact_str))//".")
281 : END IF
282 : END IF
283 : END DO
284 :
285 : ! stage 2: obtain relevant Kohn-Sham matrix blocks for each contact (separate bulk DFT calculation)
286 18 : DO icontact = 1, ncontacts
287 18 : IF (negf_control%contacts(icontact)%force_env_index > 0) THEN
288 4 : IF (negf_control%contacts(icontact)%read_write_HS) THEN
289 : CALL negf_env_contact_read_write_hs &
290 : (icontact, sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, &
291 0 : para_env, negf_env, sub_env, negf_control, negf_section, log_unit, is_separate=.TRUE.)
292 : ELSE
293 4 : IF (log_unit > 0) THEN
294 2 : WRITE (log_unit, '(/,T2,A,T70,I11,/,A)') "NEGF| Construct the Kohn-Sham matrix for the contact", icontact, &
295 4 : " from the separate bulk DFT calculation"
296 : END IF
297 4 : CALL force_env_get(sub_force_env(negf_control%contacts(icontact)%force_env_index)%force_env, qs_env=qs_env_contact)
298 4 : CALL qs_energies(qs_env_contact, consistent_energies=.FALSE., calc_forces=.FALSE.)
299 : CALL negf_env_contact_init_matrices(contact_env=negf_env%contacts(icontact), sub_env=sub_env, &
300 4 : qs_env_contact=qs_env_contact)
301 4 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
302 : END IF
303 : END IF
304 : END DO
305 :
306 : ! *** obtain relevant Kohn-Sham matrix blocks for each contact with no separate FORCE_ENV ***
307 6 : is_dft_entire = .FALSE.
308 18 : DO icontact = 1, ncontacts
309 18 : IF (negf_control%contacts(icontact)%force_env_index <= 0) THEN
310 8 : IF (negf_control%contacts(icontact)%read_write_HS) THEN
311 : CALL negf_env_contact_init_matrices_gamma(contact_env=negf_env%contacts(icontact), &
312 : contact_control=negf_control%contacts(icontact), &
313 : sub_env=sub_env, qs_env=qs_env, &
314 0 : eps_geometry=negf_control%eps_geometry)
315 : CALL negf_env_contact_read_write_hs(icontact, force_env, para_env, negf_env, sub_env, negf_control, negf_section, &
316 0 : log_unit, is_separate=.FALSE., is_dft_entire=is_dft_entire)
317 : ELSE
318 8 : IF (log_unit > 0) THEN
319 4 : WRITE (log_unit, '(/,T2,A,T70,I11,/,A)') "NEGF| Construct the Kohn-Sham matrix for the contact", icontact, &
320 8 : " from the entire system bulk DFT calculation"
321 : END IF
322 8 : IF (.NOT. is_dft_entire) CALL qs_energies(qs_env, consistent_energies=.FALSE., calc_forces=.FALSE.)
323 8 : is_dft_entire = .TRUE.
324 : CALL negf_env_contact_init_matrices_gamma(contact_env=negf_env%contacts(icontact), &
325 : contact_control=negf_control%contacts(icontact), &
326 : sub_env=sub_env, qs_env=qs_env, &
327 8 : eps_geometry=negf_control%eps_geometry)
328 8 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
329 : END IF
330 : END IF
331 : END DO
332 :
333 : ! stage 3: obtain an initial KS-matrix for the scattering region
334 6 : IF (log_unit > 0) THEN
335 3 : WRITE (log_unit, '(/,T2,A,T70)') "NEGF| Construct the Kohn-Sham matrix for the scattering region"
336 : END IF
337 6 : IF (negf_control%read_write_HS) THEN
338 : CALL negf_env_scatt_read_write_hs(force_env, para_env, negf_env, sub_env, negf_control, negf_section, log_unit, &
339 0 : is_dft_entire=is_dft_entire)
340 : ELSE
341 6 : IF (.NOT. is_dft_entire) THEN
342 2 : CALL qs_energies(qs_env, consistent_energies=.FALSE., calc_forces=.FALSE.)
343 2 : is_dft_entire = .TRUE.
344 : END IF
345 : ! extract device-related matrix blocks
346 6 : CALL negf_env_device_init_matrices(negf_env, negf_control, sub_env, qs_env)
347 : END IF
348 6 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
349 :
350 6 : negf_control%is_dft_entire = is_dft_entire
351 :
352 : ! electron density mixing;
353 : ! the input section below should be consistent with the subroutine create_negf_section()
354 6 : NULLIFY (negf_env%mixing_storage)
355 6 : CALL section_vals_val_get(negf_mixing_section, "METHOD", i_val=negf_env%mixing_method)
356 :
357 6 : CALL get_qs_env(qs_env, dft_control=dft_control)
358 24 : ALLOCATE (negf_env%mixing_storage)
359 : CALL mixing_storage_create(negf_env%mixing_storage, negf_mixing_section, &
360 6 : negf_env%mixing_method, dft_control%qs_control%cutoff)
361 :
362 6 : CALL timestop(handle)
363 24 : END SUBROUTINE negf_env_create
364 :
365 : ! **************************************************************************************************
366 : !> \brief Establish mapping between the primary and the contact force environments
367 : !> \param contact_env NEGF environment for the given contact (modified on exit)
368 : !> \param contact_control NEGF control
369 : !> \param atom_map atomic map
370 : !> \param eps_geometry accuracy in mapping atoms between different force environments
371 : !> \param subsys_device QuickStep subsystem of the device force environment
372 : !> \param subsys_contact QuickStep subsystem of the contact force environment
373 : !> \author Sergey Chulkov
374 : ! **************************************************************************************************
375 4 : SUBROUTINE negf_env_contact_init_maps(contact_env, contact_control, atom_map, &
376 : eps_geometry, subsys_device, subsys_contact)
377 : TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
378 : TYPE(negf_control_contact_type), INTENT(in) :: contact_control
379 : TYPE(negf_atom_map_type), ALLOCATABLE, &
380 : DIMENSION(:), INTENT(inout) :: atom_map
381 : REAL(kind=dp), INTENT(in) :: eps_geometry
382 : TYPE(qs_subsys_type), POINTER :: subsys_device, subsys_contact
383 :
384 : CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_contact_init_maps'
385 :
386 : INTEGER :: handle, natoms
387 :
388 4 : CALL timeset(routineN, handle)
389 :
390 : CALL contact_direction_vector(contact_env%origin, &
391 : contact_env%direction_vector, &
392 : contact_env%origin_bias, &
393 : contact_env%direction_vector_bias, &
394 : contact_control%atomlist_screening, &
395 : contact_control%atomlist_bulk, &
396 4 : subsys_device)
397 :
398 4 : contact_env%direction_axis = contact_direction_axis(contact_env%direction_vector, subsys_contact, eps_geometry)
399 :
400 4 : IF (contact_env%direction_axis /= 0) THEN
401 4 : natoms = SIZE(contact_control%atomlist_bulk)
402 56 : ALLOCATE (atom_map(natoms))
403 :
404 : ! map atom listed in 'contact_control%atomlist_bulk' to the corresponding atom/cell replica from the contact force_env
405 : CALL negf_map_atomic_indices(atom_map=atom_map, &
406 : atom_list=contact_control%atomlist_bulk, &
407 : subsys_device=subsys_device, &
408 : subsys_contact=subsys_contact, &
409 4 : eps_geometry=eps_geometry)
410 :
411 : ! list atoms from 'contact_control%atomlist_bulk' which belong to
412 : ! the primary unit cell of the bulk region for the given contact
413 : CALL list_atoms_in_bulk_primary_unit_cell(atomlist_cell0=contact_env%atomlist_cell0, &
414 : atom_map_cell0=contact_env%atom_map_cell0, &
415 : atomlist_bulk=contact_control%atomlist_bulk, &
416 : atom_map=atom_map, &
417 : origin=contact_env%origin, &
418 : direction_vector=contact_env%direction_vector, &
419 : direction_axis=contact_env%direction_axis, &
420 4 : subsys_device=subsys_device)
421 :
422 : ! secondary unit cell
423 : CALL list_atoms_in_bulk_secondary_unit_cell(atomlist_cell1=contact_env%atomlist_cell1, &
424 : atom_map_cell1=contact_env%atom_map_cell1, &
425 : atomlist_bulk=contact_control%atomlist_bulk, &
426 : atom_map=atom_map, &
427 : origin=contact_env%origin, &
428 : direction_vector=contact_env%direction_vector, &
429 : direction_axis=contact_env%direction_axis, &
430 4 : subsys_device=subsys_device)
431 : END IF
432 :
433 4 : CALL timestop(handle)
434 4 : END SUBROUTINE negf_env_contact_init_maps
435 :
436 : ! **************************************************************************************************
437 : !> \brief Reading and writing of the electrode Hamiltonian and overlap matrices from/to a file.
438 : !> \param icontact ...
439 : !> \param el_force_env ...
440 : !> \param para_env ...
441 : !> \param negf_env ...
442 : !> \param sub_env ...
443 : !> \param negf_control ...
444 : !> \param negf_section ...
445 : !> \param log_unit ...
446 : !> \param is_separate ...
447 : !> \param is_dft_entire ...
448 : !> \par History
449 : !> * 12.2025 created [Dmitry Ryndyk]
450 : ! **************************************************************************************************
451 0 : SUBROUTINE negf_env_contact_read_write_hs(icontact, el_force_env, para_env, negf_env, sub_env, negf_control, &
452 : negf_section, log_unit, is_separate, is_dft_entire)
453 : INTEGER :: icontact
454 : TYPE(force_env_type), POINTER :: el_force_env
455 : TYPE(mp_para_env_type), POINTER :: para_env
456 : TYPE(negf_env_type), INTENT(inout) :: negf_env
457 : TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
458 : TYPE(negf_control_type), POINTER :: negf_control
459 : TYPE(section_vals_type), POINTER :: negf_section
460 : INTEGER, INTENT(in) :: log_unit
461 : LOGICAL, INTENT(in) :: is_separate
462 : LOGICAL, INTENT(inout), OPTIONAL :: is_dft_entire
463 :
464 : CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_contact_read_write_hs'
465 :
466 : CHARACTER(len=default_path_length) :: filename_h00_1, filename_h00_2, &
467 : filename_h01_1, filename_h01_2, &
468 : filename_s00, filename_s01
469 : INTEGER :: handle, ispin, ncol, nrow, nspins, &
470 : print_unit
471 : LOGICAL :: exist, exist_all
472 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: target_m
473 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
474 : TYPE(cp_logger_type), POINTER :: logger
475 : TYPE(dft_control_type), POINTER :: dft_control
476 : TYPE(qs_environment_type), POINTER :: qs_env_contact
477 : TYPE(qs_subsys_type), POINTER :: subsys
478 :
479 0 : CALL timeset(routineN, handle)
480 0 : logger => cp_get_default_logger()
481 :
482 0 : CALL force_env_get(el_force_env, qs_env=qs_env_contact)
483 0 : CALL get_qs_env(qs_env_contact, dft_control=dft_control, subsys=subsys)
484 0 : nspins = dft_control%nspins
485 :
486 0 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,A,T70,I11)') &
487 0 : "NEGF| Construct the Kohn-Sham matrix for the contact", icontact
488 :
489 : ! Check that the files exist.
490 : ! ispin=0 is used to show nspins=1
491 0 : exist_all = .TRUE.
492 0 : IF (para_env%is_source()) THEN
493 0 : CALL negf_restart_file_name(filename_s00, exist, negf_section, logger, icontact, s00=.TRUE.)
494 0 : IF (.NOT. exist) THEN
495 : CALL cp_warn(__LOCATION__, &
496 : "User requested to read the overlap matrix from the file named: "// &
497 0 : TRIM(filename_s00)//". This file does not exist. The file will be created.")
498 0 : exist_all = .FALSE.
499 : END IF
500 0 : CALL negf_restart_file_name(filename_s01, exist, negf_section, logger, icontact, s01=.TRUE.)
501 0 : IF (.NOT. exist) THEN
502 : CALL cp_warn(__LOCATION__, &
503 : "User requested to read the overlap matrix from the file named: "// &
504 0 : TRIM(filename_s01)//". This file does not exist. The file will be created.")
505 0 : exist_all = .FALSE.
506 : END IF
507 0 : IF (nspins == 1) THEN
508 0 : CALL negf_restart_file_name(filename_h00_1, exist, negf_section, logger, icontact, ispin=0, h00=.TRUE.)
509 0 : IF (.NOT. exist) THEN
510 : CALL cp_warn(__LOCATION__, &
511 : "User requested to read the Hamiltonian matrix from the file named: "// &
512 0 : TRIM(filename_h00_1)//". This file does not exist. The file will be created.")
513 0 : exist_all = .FALSE.
514 : END IF
515 0 : CALL negf_restart_file_name(filename_h01_1, exist, negf_section, logger, icontact, ispin=0, h01=.TRUE.)
516 0 : IF (.NOT. exist) THEN
517 : CALL cp_warn(__LOCATION__, &
518 : "User requested to read the Hamiltonian matrix from the file named: "// &
519 0 : TRIM(filename_h01_1)//". This file does not exist. The file will be created.")
520 0 : exist_all = .FALSE.
521 : END IF
522 : END IF
523 0 : IF (nspins == 2) THEN
524 0 : CALL negf_restart_file_name(filename_h00_1, exist, negf_section, logger, icontact, ispin=1, h00=.TRUE.)
525 0 : IF (.NOT. exist) THEN
526 : CALL cp_warn(__LOCATION__, &
527 : "User requested to read the Hamiltonian matrix from the file named: "// &
528 0 : TRIM(filename_h00_1)//". This file does not exist. The file will be created.")
529 0 : exist_all = .FALSE.
530 : END IF
531 0 : CALL negf_restart_file_name(filename_h01_1, exist, negf_section, logger, icontact, ispin=1, h01=.TRUE.)
532 0 : IF (.NOT. exist) THEN
533 : CALL cp_warn(__LOCATION__, &
534 : "User requested to read tthe Hamiltonian matrix from the file named: "// &
535 0 : TRIM(filename_h01_1)//". This file does not exist. The file will be created.")
536 0 : exist_all = .FALSE.
537 : END IF
538 0 : CALL negf_restart_file_name(filename_h00_2, exist, negf_section, logger, icontact, ispin=2, h00=.TRUE.)
539 0 : IF (.NOT. exist) THEN
540 : CALL cp_warn(__LOCATION__, &
541 : "User requested to read the Hamiltonian matrix from the file named: "// &
542 0 : TRIM(filename_h00_2)//". This file does not exist. The file will be created.")
543 0 : exist_all = .FALSE.
544 : END IF
545 0 : CALL negf_restart_file_name(filename_h01_2, exist, negf_section, logger, icontact, ispin=2, h01=.TRUE.)
546 0 : IF (.NOT. exist) THEN
547 : CALL cp_warn(__LOCATION__, &
548 : "User requested to read the Hamiltonian matrix from the file named: "// &
549 0 : TRIM(filename_h01_2)//". This file does not exist. The file will be created.")
550 0 : exist_all = .FALSE.
551 : END IF
552 : END IF
553 : END IF
554 0 : CALL para_env%bcast(exist_all)
555 :
556 0 : IF (exist_all) THEN
557 :
558 0 : negf_control%contacts(icontact)%is_restart = .TRUE.
559 0 : IF (log_unit > 0) THEN
560 0 : WRITE (log_unit, '(/,T2,A)') "User requested to read the Hamiltonian and overlap matrices from files."
561 0 : WRITE (log_unit, '(T2,A)') "All restart files exist."
562 : END IF
563 :
564 : ! ++ create matrices: s_00, s_01, h_00, h_01
565 0 : IF (para_env%is_source()) THEN
566 : CALL open_file(file_name=filename_s00, file_status="OLD", &
567 : file_form="FORMATTED", file_action="READ", &
568 0 : file_position="REWIND", unit_number=print_unit)
569 0 : READ (print_unit, *) nrow, ncol
570 0 : CALL close_file(print_unit)
571 : END IF
572 0 : CALL para_env%bcast(nrow)
573 0 : CALL para_env%bcast(ncol)
574 0 : NULLIFY (fm_struct)
575 0 : CALL cp_fm_struct_create(fm_struct, nrow_global=nrow, ncol_global=ncol, context=sub_env%blacs_env)
576 0 : ALLOCATE (negf_env%contacts(icontact)%s_00, negf_env%contacts(icontact)%s_01)
577 0 : CALL cp_fm_create(negf_env%contacts(icontact)%s_00, fm_struct)
578 0 : CALL cp_fm_create(negf_env%contacts(icontact)%s_01, fm_struct)
579 0 : ALLOCATE (negf_env%contacts(icontact)%h_00(nspins), negf_env%contacts(icontact)%h_01(nspins))
580 0 : DO ispin = 1, nspins
581 0 : CALL cp_fm_create(negf_env%contacts(icontact)%h_00(ispin), fm_struct)
582 0 : CALL cp_fm_create(negf_env%contacts(icontact)%h_01(ispin), fm_struct)
583 : END DO
584 0 : CALL cp_fm_struct_release(fm_struct)
585 :
586 0 : ALLOCATE (target_m(nrow, ncol))
587 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_s00, target_m)
588 0 : CALL para_env%bcast(target_m)
589 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%s_00, target_m)
590 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_00 is read from "//TRIM(filename_s00)
591 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_s01, target_m)
592 0 : CALL para_env%bcast(target_m)
593 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%s_01, target_m)
594 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_01 is read from "//TRIM(filename_s01)
595 0 : IF (nspins == 1) THEN
596 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h00_1, target_m)
597 0 : CALL para_env%bcast(target_m)
598 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
599 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is read from "//TRIM(filename_h00_1)
600 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h01_1, target_m)
601 0 : CALL para_env%bcast(target_m)
602 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
603 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is read from "//TRIM(filename_H01_1)
604 : END IF
605 0 : IF (nspins == 2) THEN
606 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h00_1, target_m)
607 0 : CALL para_env%bcast(target_m)
608 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
609 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is read from "//TRIM(filename_h00_1)//" for spin 1"
610 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h01_1, target_m)
611 0 : CALL para_env%bcast(target_m)
612 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
613 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is read from "//TRIM(filename_H01_1)//" for spin 1"
614 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h00_2, target_m)
615 0 : CALL para_env%bcast(target_m)
616 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_00(2), target_m)
617 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is read from "//TRIM(filename_h00_2)//" for spin 2"
618 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h01_2, target_m)
619 0 : CALL para_env%bcast(target_m)
620 0 : CALL cp_fm_set_submatrix(negf_env%contacts(icontact)%h_01(2), target_m)
621 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is read from "//TRIM(filename_H01_2)//" for spin 2"
622 : END IF
623 0 : DEALLOCATE (target_m)
624 :
625 : ELSE
626 :
627 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') &
628 0 : "Some restart files do not exist. ALL restart files will be recalculated!"
629 :
630 0 : IF (is_separate) THEN
631 0 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,A,T70,I11,/,A)') &
632 0 : "Construct the Kohn-Sham matrix from from the separate bulk DFT calculation"
633 0 : CALL qs_energies(qs_env_contact, consistent_energies=.FALSE., calc_forces=.FALSE.)
634 : CALL negf_env_contact_init_matrices(contact_env=negf_env%contacts(icontact), sub_env=sub_env, &
635 0 : qs_env_contact=qs_env_contact)
636 : ELSE
637 0 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,A,T70,I11,/,A)') &
638 0 : "Construct the Kohn-Sham matrix from the entire system bulk DFT calculation"
639 0 : negf_control%contacts(icontact)%read_write_HS = .FALSE.
640 0 : IF (.NOT. is_dft_entire) CALL qs_energies(qs_env_contact, consistent_energies=.FALSE., calc_forces=.FALSE.)
641 : CALL negf_env_contact_init_matrices_gamma(contact_env=negf_env%contacts(icontact), &
642 : contact_control=negf_control%contacts(icontact), &
643 : sub_env=sub_env, qs_env=qs_env_contact, &
644 0 : eps_geometry=negf_control%eps_geometry)
645 0 : negf_control%contacts(icontact)%read_write_HS = .TRUE.
646 0 : is_dft_entire = .TRUE.
647 : END IF
648 :
649 0 : CALL cp_fm_get_info(negf_env%contacts(icontact)%s_00, nrow_global=nrow)
650 0 : ALLOCATE (target_m(nrow, nrow))
651 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%s_00, target_m)
652 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_s00, target_m)
653 0 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,A)') "S_00 is saved to "//TRIM(filename_s00)
654 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%s_01, target_m)
655 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_s01, target_m)
656 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_01 is saved to "//TRIM(filename_s01)
657 0 : IF (nspins == 1) THEN
658 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
659 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h00_1, target_m)
660 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is saved to "//TRIM(filename_h00_1)
661 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
662 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h01_1, target_m)
663 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is saved to "//TRIM(filename_h01_1)
664 : END IF
665 0 : IF (nspins == 2) THEN
666 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_00(1), target_m)
667 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h00_1, target_m)
668 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is saved to "//TRIM(filename_h00_1)//" for spin 1"
669 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_01(1), target_m)
670 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h01_1, target_m)
671 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is saved to "//TRIM(filename_h01_1)//" for spin 1"
672 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_00(2), target_m)
673 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h00_2, target_m)
674 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_00 is saved to "//TRIM(filename_h00_2)//" for spin 2"
675 0 : CALL cp_fm_get_submatrix(negf_env%contacts(icontact)%h_01(2), target_m)
676 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h01_2, target_m)
677 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_01 is saved to "//TRIM(filename_h01_2)//" for spin 2"
678 : END IF
679 0 : DEALLOCATE (target_m)
680 :
681 0 : negf_control%write_common_restart_file = .TRUE.
682 :
683 : END IF
684 :
685 0 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,79("-"))')
686 :
687 0 : CALL timestop(handle)
688 0 : END SUBROUTINE negf_env_contact_read_write_hs
689 :
690 : ! **************************************************************************************************
691 : !> \brief Extract relevant matrix blocks for the given contact.
692 : !> \param contact_env NEGF environment for the contact (modified on exit)
693 : !> \param sub_env NEGF parallel (sub)group environment
694 : !> \param qs_env_contact QuickStep environment for the contact force environment
695 : !> \par History
696 : !> * 10.2017 created [Sergey Chulkov]
697 : !> * 10.2025 The subroutine is essentially modified. New functionality of negf_copy_contact_matrix.
698 : !> [Dmitry Ryndyk]
699 : ! **************************************************************************************************
700 4 : SUBROUTINE negf_env_contact_init_matrices(contact_env, sub_env, qs_env_contact)
701 : TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
702 : TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
703 : TYPE(qs_environment_type), POINTER :: qs_env_contact
704 :
705 : CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_contact_init_matrices'
706 :
707 : INTEGER :: handle, iatom, ispin, nao, natoms, &
708 : nimages, nspins
709 4 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_list0, atom_list1
710 4 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: index_to_cell
711 4 : INTEGER, DIMENSION(:, :, :), POINTER :: cell_to_index
712 : LOGICAL :: do_kpoints
713 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
714 4 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matkp
715 4 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp, rho_ao_kp
716 : TYPE(dft_control_type), POINTER :: dft_control
717 : TYPE(kpoint_type), POINTER :: kpoints
718 : TYPE(mp_para_env_type), POINTER :: para_env
719 : TYPE(qs_rho_type), POINTER :: rho_struct
720 : TYPE(qs_subsys_type), POINTER :: subsys
721 :
722 4 : CALL timeset(routineN, handle)
723 :
724 : CALL get_qs_env(qs_env_contact, &
725 : dft_control=dft_control, &
726 : do_kpoints=do_kpoints, &
727 : kpoints=kpoints, &
728 : matrix_ks_kp=matrix_ks_kp, &
729 : matrix_s_kp=matrix_s_kp, &
730 : para_env=para_env, &
731 : rho=rho_struct, &
732 4 : subsys=subsys)
733 4 : CALL qs_rho_get(rho_struct, rho_ao_kp=rho_ao_kp)
734 :
735 4 : CALL negf_homo_energy_estimate(contact_env%homo_energy, qs_env_contact)
736 :
737 4 : natoms = SIZE(contact_env%atomlist_cell0)
738 12 : ALLOCATE (atom_list0(natoms))
739 20 : DO iatom = 1, natoms
740 16 : atom_list0(iatom) = contact_env%atom_map_cell0(iatom)%iatom
741 :
742 : ! with no k-points there is one-to-one correspondence between the primary unit cell
743 : ! of the contact force_env and the first contact unit cell of the device force_env
744 68 : IF (SUM(ABS(contact_env%atom_map_cell0(iatom)%cell(:))) > 0) THEN
745 0 : CPABORT("NEGF K-points are not currently supported")
746 : END IF
747 : END DO
748 :
749 4 : CPASSERT(SIZE(contact_env%atomlist_cell1) == natoms)
750 8 : ALLOCATE (atom_list1(natoms))
751 20 : DO iatom = 1, natoms
752 20 : atom_list1(iatom) = contact_env%atom_map_cell1(iatom)%iatom
753 : END DO
754 :
755 4 : nspins = dft_control%nspins
756 4 : nimages = dft_control%nimages
757 :
758 4 : IF (do_kpoints) THEN
759 4 : CALL get_kpoint_info(kpoints, cell_to_index=cell_to_index)
760 : ELSE
761 0 : ALLOCATE (cell_to_index(0:0, 0:0, 0:0))
762 0 : cell_to_index(0, 0, 0) = 1
763 : END IF
764 :
765 12 : ALLOCATE (index_to_cell(3, nimages))
766 4 : CALL invert_cell_to_index(cell_to_index, nimages, index_to_cell)
767 4 : IF (.NOT. do_kpoints) DEALLOCATE (cell_to_index)
768 :
769 4 : NULLIFY (fm_struct)
770 4 : nao = number_of_atomic_orbitals(subsys, atom_list0)
771 4 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nao, context=sub_env%blacs_env)
772 :
773 : ! ++ create matrices: s_00, s_01
774 4 : ALLOCATE (contact_env%s_00, contact_env%s_01)
775 4 : CALL cp_fm_create(contact_env%s_00, fm_struct)
776 4 : CALL cp_fm_create(contact_env%s_01, fm_struct)
777 :
778 : ! ++ create matrices: h_00, h_01, rho_00, rho_01
779 24 : ALLOCATE (contact_env%h_00(nspins), contact_env%h_01(nspins))
780 20 : ALLOCATE (contact_env%rho_00(nspins), contact_env%rho_01(nspins))
781 8 : DO ispin = 1, nspins
782 4 : CALL cp_fm_create(contact_env%h_00(ispin), fm_struct)
783 4 : CALL cp_fm_create(contact_env%h_01(ispin), fm_struct)
784 4 : CALL cp_fm_create(contact_env%rho_00(ispin), fm_struct)
785 8 : CALL cp_fm_create(contact_env%rho_01(ispin), fm_struct)
786 : END DO
787 :
788 4 : CALL cp_fm_struct_release(fm_struct)
789 :
790 : ! extract matrices: s_00, s_01
791 4 : matkp => matrix_s_kp(1, :)
792 : CALL negf_copy_contact_matrix(fm_cell0=contact_env%s_00, &
793 : fm_cell1=contact_env%s_01, &
794 : direction_axis=contact_env%direction_axis, &
795 : matrix_kp=matkp, &
796 : atom_list0=atom_list0, atom_list1=atom_list1, &
797 : subsys=subsys, mpi_comm_global=para_env, &
798 4 : kpoints=kpoints)
799 :
800 : ! extract matrices: h_00, h_01, rho_00, rho_01
801 8 : DO ispin = 1, nspins
802 4 : matkp => matrix_ks_kp(ispin, :)
803 : CALL negf_copy_contact_matrix(fm_cell0=contact_env%h_00(ispin), &
804 : fm_cell1=contact_env%h_01(ispin), &
805 : direction_axis=contact_env%direction_axis, &
806 : matrix_kp=matkp, &
807 : atom_list0=atom_list0, atom_list1=atom_list1, &
808 : subsys=subsys, mpi_comm_global=para_env, &
809 4 : kpoints=kpoints)
810 :
811 4 : matkp => rho_ao_kp(ispin, :)
812 : CALL negf_copy_contact_matrix(fm_cell0=contact_env%rho_00(ispin), &
813 : fm_cell1=contact_env%rho_01(ispin), &
814 : direction_axis=contact_env%direction_axis, &
815 : matrix_kp=matkp, &
816 : atom_list0=atom_list0, atom_list1=atom_list1, &
817 : subsys=subsys, mpi_comm_global=para_env, &
818 8 : kpoints=kpoints)
819 : END DO
820 :
821 4 : DEALLOCATE (atom_list0, atom_list1)
822 :
823 4 : CALL timestop(handle)
824 8 : END SUBROUTINE negf_env_contact_init_matrices
825 :
826 : ! **************************************************************************************************
827 : !> \brief Extract relevant matrix blocks for the given contact using the device's force environment.
828 : !> \param contact_env NEGF environment for the contact (modified on exit)
829 : !> \param contact_control NEGF control for the contact
830 : !> \param sub_env NEGF parallel (sub)group environment
831 : !> \param qs_env QuickStep environment for the device force environment
832 : !> \param eps_geometry accuracy in Cartesian coordinates
833 : !> \author Sergey Chulkov
834 : ! **************************************************************************************************
835 8 : SUBROUTINE negf_env_contact_init_matrices_gamma(contact_env, contact_control, sub_env, qs_env, eps_geometry)
836 : TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
837 : TYPE(negf_control_contact_type), INTENT(in) :: contact_control
838 : TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
839 : TYPE(qs_environment_type), POINTER :: qs_env
840 : REAL(kind=dp), INTENT(in) :: eps_geometry
841 :
842 : CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_contact_init_matrices_gamma'
843 :
844 : INTEGER :: handle, iatom, icell, ispin, nao_c, &
845 : nspins
846 : LOGICAL :: do_kpoints
847 : REAL(kind=dp), DIMENSION(2) :: r2_origin_cell
848 : REAL(kind=dp), DIMENSION(3) :: direction_vector, origin
849 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
850 8 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp, rho_ao_kp
851 : TYPE(dft_control_type), POINTER :: dft_control
852 : TYPE(mp_para_env_type), POINTER :: para_env
853 8 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
854 : TYPE(qs_rho_type), POINTER :: rho_struct
855 : TYPE(qs_subsys_type), POINTER :: subsys
856 :
857 8 : CALL timeset(routineN, handle)
858 :
859 : CALL get_qs_env(qs_env, &
860 : dft_control=dft_control, &
861 : do_kpoints=do_kpoints, &
862 : matrix_ks_kp=matrix_ks_kp, &
863 : matrix_s_kp=matrix_s_kp, &
864 : para_env=para_env, &
865 : rho=rho_struct, &
866 8 : subsys=subsys)
867 8 : CALL qs_rho_get(rho_struct, rho_ao_kp=rho_ao_kp)
868 :
869 8 : IF (do_kpoints) THEN
870 : CALL cp_abort(__LOCATION__, &
871 0 : "K-points in device region have not been implemented yet.")
872 : END IF
873 :
874 8 : nspins = dft_control%nspins
875 :
876 8 : nao_c = number_of_atomic_orbitals(subsys, contact_control%atomlist_cell(1)%vector)
877 8 : IF (number_of_atomic_orbitals(subsys, contact_control%atomlist_cell(2)%vector) /= nao_c) THEN
878 : CALL cp_abort(__LOCATION__, &
879 : "Primary and secondary bulk contact cells should be identical "// &
880 : "in terms of the number of atoms of each kind, and their basis sets. "// &
881 0 : "No single atom, however, can be shared between these two cells.")
882 : END IF
883 :
884 8 : contact_env%homo_energy = 0.0_dp
885 :
886 : CALL contact_direction_vector(contact_env%origin, &
887 : contact_env%direction_vector, &
888 : contact_env%origin_bias, &
889 : contact_env%direction_vector_bias, &
890 : contact_control%atomlist_screening, &
891 : contact_control%atomlist_bulk, &
892 8 : subsys)
893 :
894 8 : contact_env%direction_axis = contact_direction_axis(contact_env%direction_vector, subsys, eps_geometry)
895 :
896 : ! choose the primary and secondary contact unit cells
897 8 : CALL qs_subsys_get(subsys, particle_set=particle_set)
898 :
899 32 : origin = particle_set(contact_control%atomlist_screening(1))%r
900 32 : DO iatom = 2, SIZE(contact_control%atomlist_screening)
901 104 : origin = origin + particle_set(contact_control%atomlist_screening(iatom))%r
902 : END DO
903 32 : origin = origin/REAL(SIZE(contact_control%atomlist_screening), kind=dp)
904 :
905 24 : DO icell = 1, 2
906 64 : direction_vector = particle_set(contact_control%atomlist_cell(icell)%vector(1))%r
907 64 : DO iatom = 2, SIZE(contact_control%atomlist_cell(icell)%vector)
908 208 : direction_vector = direction_vector + particle_set(contact_control%atomlist_cell(icell)%vector(iatom))%r
909 : END DO
910 64 : direction_vector = direction_vector/REAL(SIZE(contact_control%atomlist_cell(icell)%vector), kind=dp)
911 64 : direction_vector = direction_vector - origin
912 72 : r2_origin_cell(icell) = DOT_PRODUCT(direction_vector, direction_vector)
913 : END DO
914 :
915 8 : IF (ABS(r2_origin_cell(1) - r2_origin_cell(2)) < (eps_geometry*eps_geometry)) THEN
916 : ! primary and secondary bulk unit cells should not overlap;
917 : ! currently we check that they are different by at least one atom that is, indeed, not sufficient.
918 : CALL cp_abort(__LOCATION__, &
919 0 : "Primary and secondary bulk contact cells should not overlap ")
920 8 : ELSE IF (r2_origin_cell(1) < r2_origin_cell(2)) THEN
921 6 : IF (.NOT. ALLOCATED(contact_env%atomlist_cell0)) THEN
922 18 : ALLOCATE (contact_env%atomlist_cell0(SIZE(contact_control%atomlist_cell(1)%vector)))
923 : END IF
924 30 : contact_env%atomlist_cell0(:) = contact_control%atomlist_cell(1)%vector(:)
925 6 : IF (.NOT. ALLOCATED(contact_env%atomlist_cell1)) THEN
926 18 : ALLOCATE (contact_env%atomlist_cell1(SIZE(contact_control%atomlist_cell(2)%vector)))
927 : END IF
928 30 : contact_env%atomlist_cell1(:) = contact_control%atomlist_cell(2)%vector(:)
929 : ELSE
930 2 : IF (.NOT. ALLOCATED(contact_env%atomlist_cell0)) THEN
931 6 : ALLOCATE (contact_env%atomlist_cell0(SIZE(contact_control%atomlist_cell(2)%vector)))
932 : END IF
933 10 : contact_env%atomlist_cell0(:) = contact_control%atomlist_cell(2)%vector(:)
934 2 : IF (.NOT. ALLOCATED(contact_env%atomlist_cell1)) THEN
935 6 : ALLOCATE (contact_env%atomlist_cell1(SIZE(contact_control%atomlist_cell(1)%vector)))
936 : END IF
937 10 : contact_env%atomlist_cell1(:) = contact_control%atomlist_cell(1)%vector(:)
938 : END IF
939 8 : IF (.NOT. contact_control%read_write_HS) THEN
940 8 : NULLIFY (fm_struct)
941 8 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao_c, ncol_global=nao_c, context=sub_env%blacs_env)
942 48 : ALLOCATE (contact_env%h_00(nspins), contact_env%h_01(nspins))
943 40 : ALLOCATE (contact_env%rho_00(nspins), contact_env%rho_01(nspins))
944 16 : DO ispin = 1, nspins
945 8 : CALL cp_fm_create(contact_env%h_00(ispin), fm_struct)
946 8 : CALL cp_fm_create(contact_env%h_01(ispin), fm_struct)
947 8 : CALL cp_fm_create(contact_env%rho_00(ispin), fm_struct)
948 16 : CALL cp_fm_create(contact_env%rho_01(ispin), fm_struct)
949 : END DO
950 8 : ALLOCATE (contact_env%s_00, contact_env%s_01)
951 8 : CALL cp_fm_create(contact_env%s_00, fm_struct)
952 8 : CALL cp_fm_create(contact_env%s_01, fm_struct)
953 8 : CALL cp_fm_struct_release(fm_struct)
954 :
955 16 : DO ispin = 1, nspins
956 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
957 : fm=contact_env%h_00(ispin), &
958 : atomlist_row=contact_env%atomlist_cell0, &
959 : atomlist_col=contact_env%atomlist_cell0, &
960 : subsys=subsys, mpi_comm_global=para_env, &
961 8 : do_upper_diag=.TRUE., do_lower=.TRUE.)
962 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
963 : fm=contact_env%h_01(ispin), &
964 : atomlist_row=contact_env%atomlist_cell0, &
965 : atomlist_col=contact_env%atomlist_cell1, &
966 : subsys=subsys, mpi_comm_global=para_env, &
967 8 : do_upper_diag=.TRUE., do_lower=.TRUE.)
968 :
969 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=rho_ao_kp(ispin, 1)%matrix, &
970 : fm=contact_env%rho_00(ispin), &
971 : atomlist_row=contact_env%atomlist_cell0, &
972 : atomlist_col=contact_env%atomlist_cell0, &
973 : subsys=subsys, mpi_comm_global=para_env, &
974 8 : do_upper_diag=.TRUE., do_lower=.TRUE.)
975 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=rho_ao_kp(ispin, 1)%matrix, &
976 : fm=contact_env%rho_01(ispin), &
977 : atomlist_row=contact_env%atomlist_cell0, &
978 : atomlist_col=contact_env%atomlist_cell1, &
979 : subsys=subsys, mpi_comm_global=para_env, &
980 16 : do_upper_diag=.TRUE., do_lower=.TRUE.)
981 : END DO
982 :
983 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
984 : fm=contact_env%s_00, &
985 : atomlist_row=contact_env%atomlist_cell0, &
986 : atomlist_col=contact_env%atomlist_cell0, &
987 : subsys=subsys, mpi_comm_global=para_env, &
988 8 : do_upper_diag=.TRUE., do_lower=.TRUE.)
989 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
990 : fm=contact_env%s_01, &
991 : atomlist_row=contact_env%atomlist_cell0, &
992 : atomlist_col=contact_env%atomlist_cell1, &
993 : subsys=subsys, mpi_comm_global=para_env, &
994 8 : do_upper_diag=.TRUE., do_lower=.TRUE.)
995 : END IF
996 8 : CALL timestop(handle)
997 8 : END SUBROUTINE negf_env_contact_init_matrices_gamma
998 :
999 : ! **************************************************************************************************
1000 : !> \brief Reading and writing of the electrode Hamiltonian and overlap matrices from/to a file.
1001 : !> \param force_env ...
1002 : !> \param para_env ...
1003 : !> \param negf_env ...
1004 : !> \param sub_env ...
1005 : !> \param negf_control ...
1006 : !> \param negf_section ...
1007 : !> \param log_unit ...
1008 : !> \param is_dft_entire ...
1009 : !> \par History
1010 : !> * 01.2026 created [Dmitry Ryndyk]
1011 : ! **************************************************************************************************
1012 0 : SUBROUTINE negf_env_scatt_read_write_hs(force_env, para_env, negf_env, sub_env, negf_control, negf_section, &
1013 : log_unit, is_dft_entire)
1014 : TYPE(force_env_type), POINTER :: force_env
1015 : TYPE(mp_para_env_type), POINTER :: para_env
1016 : TYPE(negf_env_type), INTENT(inout) :: negf_env
1017 : TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
1018 : TYPE(negf_control_type), POINTER :: negf_control
1019 : TYPE(section_vals_type), POINTER :: negf_section
1020 : INTEGER, INTENT(in) :: log_unit
1021 : LOGICAL, INTENT(inout), OPTIONAL :: is_dft_entire
1022 :
1023 : CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_scatt_read_write_hs'
1024 :
1025 : CHARACTER(len=default_path_length) :: filename_h_1, filename_h_2, filename_s
1026 : CHARACTER(len=default_path_length), ALLOCATABLE, &
1027 0 : DIMENSION(:) :: filename_hc_1, filename_hc_2, filename_sc
1028 : INTEGER :: handle, icontact, ispin, ncol_s, &
1029 : ncol_sc, ncontacts, nrow_s, nrow_sc, &
1030 : nspins, print_unit
1031 : LOGICAL :: exist, exist_all
1032 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: target_m
1033 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
1034 : TYPE(cp_logger_type), POINTER :: logger
1035 : TYPE(dft_control_type), POINTER :: dft_control
1036 : TYPE(qs_environment_type), POINTER :: qs_env
1037 : TYPE(qs_subsys_type), POINTER :: subsys
1038 :
1039 0 : CALL timeset(routineN, handle)
1040 0 : logger => cp_get_default_logger()
1041 :
1042 0 : CALL force_env_get(force_env, qs_env=qs_env)
1043 0 : CALL get_qs_env(qs_env, dft_control=dft_control, subsys=subsys)
1044 0 : ncontacts = SIZE(negf_control%contacts)
1045 0 : nspins = dft_control%nspins
1046 0 : ALLOCATE (filename_sc(ncontacts), filename_hc_1(ncontacts), filename_hc_2(ncontacts))
1047 :
1048 : ! Check that the files exist.
1049 : ! ispin=0 is used to show nspins=1
1050 0 : exist_all = .TRUE.
1051 0 : IF (para_env%is_source()) THEN
1052 0 : CALL negf_restart_file_name(filename_s, exist, negf_section, logger, s=.TRUE.)
1053 0 : IF (.NOT. exist) THEN
1054 : CALL cp_warn(__LOCATION__, &
1055 : "User requested to read the overlap matrix from the file named: "// &
1056 0 : TRIM(filename_s)//". This file does not exist. The file will be created.")
1057 0 : exist_all = .FALSE.
1058 : END IF
1059 0 : IF (nspins == 1) THEN
1060 0 : CALL negf_restart_file_name(filename_h_1, exist, negf_section, logger, ispin=0, h=.TRUE.)
1061 0 : IF (.NOT. exist) THEN
1062 : CALL cp_warn(__LOCATION__, &
1063 : "User requested to read the Hamiltonian matrix from the file named: "// &
1064 0 : TRIM(filename_h_1)//". This file does not exist. The file will be created.")
1065 0 : exist_all = .FALSE.
1066 : END IF
1067 : END IF
1068 0 : IF (nspins == 2) THEN
1069 0 : CALL negf_restart_file_name(filename_h_1, exist, negf_section, logger, ispin=1, h=.TRUE.)
1070 0 : IF (.NOT. exist) THEN
1071 : CALL cp_warn(__LOCATION__, &
1072 : "User requested to read the Hamiltonian matrix from the file named: "// &
1073 0 : TRIM(filename_h_1)//". This file does not exist. The file will be created.")
1074 0 : exist_all = .FALSE.
1075 : END IF
1076 0 : CALL negf_restart_file_name(filename_h_2, exist, negf_section, logger, ispin=2, h=.TRUE.)
1077 0 : IF (.NOT. exist) THEN
1078 : CALL cp_warn(__LOCATION__, &
1079 : "User requested to read the Hamiltonian matrix from the file named: "// &
1080 0 : TRIM(filename_h_2)//". This file does not exist. The file will be created.")
1081 0 : exist_all = .FALSE.
1082 : END IF
1083 : END IF
1084 0 : DO icontact = 1, ncontacts
1085 0 : CALL negf_restart_file_name(filename_sc(icontact), exist, negf_section, logger, icontact=icontact, sc=.TRUE.)
1086 0 : IF (.NOT. exist) THEN
1087 : CALL cp_warn(__LOCATION__, &
1088 : "User requested to read the overlap matrix from the file named: "// &
1089 0 : TRIM(filename_sc(icontact))//". This file does not exist. The file will be created.")
1090 0 : exist_all = .FALSE.
1091 : END IF
1092 0 : IF (nspins == 1) THEN
1093 : CALL negf_restart_file_name(filename_hc_1(icontact), exist, negf_section, logger, icontact=icontact, &
1094 0 : ispin=0, hc=.TRUE.)
1095 0 : IF (.NOT. exist) THEN
1096 : CALL cp_warn(__LOCATION__, &
1097 : "User requested to read the Hamiltonian matrix from the file named: "// &
1098 0 : TRIM(filename_hc_1(icontact))//". This file does not exist. The file will be created.")
1099 0 : exist_all = .FALSE.
1100 : END IF
1101 : END IF
1102 0 : IF (nspins == 2) THEN
1103 : CALL negf_restart_file_name(filename_hc_1(icontact), exist, negf_section, logger, icontact=icontact, &
1104 0 : ispin=1, hc=.TRUE.)
1105 0 : IF (.NOT. exist) THEN
1106 : CALL cp_warn(__LOCATION__, &
1107 : "User requested to read the Hamiltonian matrix from the file named: "// &
1108 0 : TRIM(filename_hc_1(icontact))//". This file does not exist. The file will be created.")
1109 0 : exist_all = .FALSE.
1110 : END IF
1111 : CALL negf_restart_file_name(filename_hc_2(icontact), exist, negf_section, logger, icontact=icontact, &
1112 0 : ispin=2, hc=.TRUE.)
1113 0 : IF (.NOT. exist) THEN
1114 : CALL cp_warn(__LOCATION__, &
1115 : "User requested to read the Hamiltonian matrix from the file named: "// &
1116 0 : TRIM(filename_hc_2(icontact))//". This file does not exist. The file will be created.")
1117 0 : exist_all = .FALSE.
1118 : END IF
1119 : END IF
1120 : END DO
1121 : END IF
1122 0 : CALL para_env%bcast(exist_all)
1123 :
1124 0 : IF (exist_all) THEN
1125 :
1126 0 : negf_control%is_restart = .TRUE.
1127 :
1128 0 : IF (log_unit > 0) THEN
1129 0 : WRITE (log_unit, '(/,T2,A)') "User requested to read the Hamiltonian and overlap matrices from files."
1130 0 : WRITE (log_unit, '(T2,A)') "All restart files exist."
1131 : END IF
1132 :
1133 : ! ++ create matrices: s_s, s_sc, h_s, h_sc
1134 0 : IF (para_env%is_source()) THEN
1135 : CALL open_file(file_name=filename_s, file_status="OLD", &
1136 : file_form="FORMATTED", file_action="READ", &
1137 0 : file_position="REWIND", unit_number=print_unit)
1138 0 : READ (print_unit, *) nrow_s, ncol_s
1139 0 : CALL close_file(print_unit)
1140 : END IF
1141 0 : CALL para_env%bcast(nrow_s)
1142 0 : CALL para_env%bcast(ncol_s)
1143 0 : NULLIFY (fm_struct)
1144 0 : CALL cp_fm_struct_create(fm_struct, nrow_global=nrow_s, ncol_global=ncol_s, context=sub_env%blacs_env)
1145 0 : ALLOCATE (negf_env%s_s)
1146 0 : CALL cp_fm_create(negf_env%s_s, fm_struct)
1147 0 : ALLOCATE (negf_env%h_s(nspins))
1148 0 : DO ispin = 1, nspins
1149 0 : CALL cp_fm_create(negf_env%h_s(ispin), fm_struct)
1150 : END DO
1151 0 : CALL cp_fm_struct_release(fm_struct)
1152 0 : ALLOCATE (negf_env%s_sc(ncontacts))
1153 0 : ALLOCATE (negf_env%h_sc(nspins, ncontacts))
1154 0 : DO icontact = 1, ncontacts
1155 0 : IF (para_env%is_source()) THEN
1156 : CALL open_file(file_name=filename_sc(icontact), file_status="OLD", &
1157 : file_form="FORMATTED", file_action="READ", &
1158 0 : file_position="REWIND", unit_number=print_unit)
1159 0 : READ (print_unit, *) nrow_sc, ncol_sc
1160 0 : CALL close_file(print_unit)
1161 : END IF
1162 0 : CALL para_env%bcast(nrow_sc)
1163 0 : CALL para_env%bcast(ncol_sc)
1164 0 : NULLIFY (fm_struct)
1165 0 : CALL cp_fm_struct_create(fm_struct, nrow_global=nrow_sc, ncol_global=ncol_sc, context=sub_env%blacs_env)
1166 0 : CALL cp_fm_create(negf_env%s_sc(icontact), fm_struct)
1167 0 : DO ispin = 1, nspins
1168 0 : CALL cp_fm_create(negf_env%h_sc(ispin, icontact), fm_struct)
1169 : END DO
1170 0 : CALL cp_fm_struct_release(fm_struct)
1171 : END DO
1172 :
1173 0 : ALLOCATE (target_m(nrow_s, ncol_s))
1174 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_s, target_m)
1175 0 : CALL para_env%bcast(target_m)
1176 0 : CALL cp_fm_set_submatrix(negf_env%s_s, target_m)
1177 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_s is read from "//TRIM(filename_s)
1178 0 : IF (nspins == 1) THEN
1179 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h_1, target_m)
1180 0 : CALL para_env%bcast(target_m)
1181 0 : CALL cp_fm_set_submatrix(negf_env%h_s(1), target_m)
1182 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_s is read from "//TRIM(filename_h_1)
1183 : END IF
1184 0 : IF (nspins == 2) THEN
1185 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h_1, target_m)
1186 0 : CALL para_env%bcast(target_m)
1187 0 : CALL cp_fm_set_submatrix(negf_env%h_s(1), target_m)
1188 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_s is read from "//TRIM(filename_h_1)//" for spin 1"
1189 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_h_2, target_m)
1190 0 : CALL para_env%bcast(target_m)
1191 0 : CALL cp_fm_set_submatrix(negf_env%h_s(2), target_m)
1192 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_s is read from "//TRIM(filename_h_2)//" for spin 2"
1193 : END IF
1194 0 : DEALLOCATE (target_m)
1195 :
1196 0 : DO icontact = 1, ncontacts
1197 0 : ALLOCATE (target_m(nrow_s, ncol_sc))
1198 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_sc(icontact), target_m)
1199 0 : CALL para_env%bcast(target_m)
1200 0 : CALL cp_fm_set_submatrix(negf_env%s_sc(icontact), target_m)
1201 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "S_sc is read from "//TRIM(filename_sc(icontact))
1202 0 : IF (nspins == 1) THEN
1203 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_hc_1(icontact), target_m)
1204 0 : CALL para_env%bcast(target_m)
1205 0 : CALL cp_fm_set_submatrix(negf_env%h_sc(1, icontact), target_m)
1206 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_sc is read from "//TRIM(filename_hc_1(icontact))
1207 : END IF
1208 0 : IF (nspins == 2) THEN
1209 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_hc_1(icontact), target_m)
1210 0 : CALL para_env%bcast(target_m)
1211 0 : CALL cp_fm_set_submatrix(negf_env%h_sc(1, icontact), target_m)
1212 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_sc is read from "//TRIM(filename_hc_1(icontact))//" for spin 1"
1213 0 : IF (para_env%is_source()) CALL negf_read_matrix_from_file(filename_hc_2(icontact), target_m)
1214 0 : CALL para_env%bcast(target_m)
1215 0 : CALL cp_fm_set_submatrix(negf_env%h_sc(2, icontact), target_m)
1216 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_sc is read from "//TRIM(filename_hc_2(icontact))//" for spin 2"
1217 : END IF
1218 0 : DEALLOCATE (target_m)
1219 :
1220 : END DO
1221 :
1222 : ELSE
1223 :
1224 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') &
1225 0 : "Some restart files do not exist. ALL restart files will be recalculated!"
1226 :
1227 0 : IF (.NOT. is_dft_entire) CALL qs_energies(qs_env, consistent_energies=.FALSE., calc_forces=.FALSE.)
1228 : ! extract device-related matrix blocks
1229 0 : CALL negf_env_device_init_matrices(negf_env, negf_control, sub_env, qs_env)
1230 0 : is_dft_entire = .TRUE.
1231 :
1232 0 : CALL cp_fm_get_info(negf_env%s_s, nrow_global=nrow_s, ncol_global=ncol_s)
1233 0 : ALLOCATE (target_m(nrow_s, ncol_s))
1234 0 : CALL cp_fm_get_submatrix(negf_env%s_s, target_m)
1235 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_s, target_m)
1236 0 : IF (log_unit > 0) WRITE (log_unit, '(/,T2,A)') "S_s is saved to "//TRIM(filename_s)
1237 0 : IF (nspins == 1) THEN
1238 0 : CALL cp_fm_get_submatrix(negf_env%h_s(1), target_m)
1239 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h_1, target_m)
1240 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_s is saved to "//TRIM(filename_h_1)
1241 : END IF
1242 0 : IF (nspins == 2) THEN
1243 0 : CALL cp_fm_get_submatrix(negf_env%h_s(1), target_m)
1244 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h_1, target_m)
1245 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_s is saved to "//TRIM(filename_h_1)//" for spin 1"
1246 0 : CALL cp_fm_get_submatrix(negf_env%h_s(2), target_m)
1247 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_h_2, target_m)
1248 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_s is saved to "//TRIM(filename_h_2)//" for spin 2"
1249 : END IF
1250 0 : DEALLOCATE (target_m)
1251 :
1252 0 : DO icontact = 1, ncontacts
1253 0 : CALL cp_fm_get_info(negf_env%contacts(icontact)%s_00, nrow_global=nrow_sc, ncol_global=ncol_sc)
1254 0 : ALLOCATE (target_m(nrow_s, ncol_sc))
1255 0 : CALL cp_fm_get_submatrix(negf_env%s_sc(icontact), target_m)
1256 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_sc(icontact), target_m)
1257 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A,I3)') &
1258 0 : "S_sc is saved to "//TRIM(filename_sc(icontact))//" for contact", icontact
1259 0 : IF (nspins == 1) THEN
1260 0 : CALL cp_fm_get_submatrix(negf_env%h_sc(1, icontact), target_m)
1261 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_hc_1(icontact), target_m)
1262 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_sc is saved to "//TRIM(filename_hc_1(icontact))
1263 : END IF
1264 0 : IF (nspins == 2) THEN
1265 0 : CALL cp_fm_get_submatrix(negf_env%h_sc(1, icontact), target_m)
1266 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_hc_1(icontact), target_m)
1267 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_sc is saved to "//TRIM(filename_hc_1(icontact))//" for spin 1"
1268 0 : CALL cp_fm_get_submatrix(negf_env%h_sc(2, icontact), target_m)
1269 0 : IF (para_env%is_source()) CALL negf_print_matrix_to_file(filename_hc_2(icontact), target_m)
1270 0 : IF (log_unit > 0) WRITE (log_unit, '(T2,A)') "H_sc is saved to "//TRIM(filename_hc_2(icontact))//" for spin 2"
1271 : END IF
1272 0 : DEALLOCATE (target_m)
1273 : END DO
1274 :
1275 0 : negf_control%write_common_restart_file = .TRUE.
1276 :
1277 : END IF
1278 :
1279 0 : DEALLOCATE (filename_sc, filename_hc_1, filename_hc_2)
1280 0 : CALL timestop(handle)
1281 0 : END SUBROUTINE negf_env_scatt_read_write_hs
1282 :
1283 : ! **************************************************************************************************
1284 : !> \brief Extract relevant matrix blocks for the scattering region as well as
1285 : !> all the scattering -- contact interface regions.
1286 : !> \param negf_env NEGF environment (modified on exit)
1287 : !> \param negf_control NEGF control
1288 : !> \param sub_env NEGF parallel (sub)group environment
1289 : !> \param qs_env Primary QuickStep environment
1290 : !> \author Sergey Chulkov
1291 : ! **************************************************************************************************
1292 6 : SUBROUTINE negf_env_device_init_matrices(negf_env, negf_control, sub_env, qs_env)
1293 : TYPE(negf_env_type), INTENT(inout) :: negf_env
1294 : TYPE(negf_control_type), POINTER :: negf_control
1295 : TYPE(negf_subgroup_env_type), INTENT(in) :: sub_env
1296 : TYPE(qs_environment_type), POINTER :: qs_env
1297 :
1298 : CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_env_device_init_matrices'
1299 :
1300 : INTEGER :: handle, icontact, ispin, nao_c, nao_s, &
1301 : ncontacts, nspins
1302 : LOGICAL :: do_kpoints
1303 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
1304 : TYPE(dbcsr_p_type) :: hmat
1305 6 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: matrix_ks_kp, matrix_s_kp
1306 : TYPE(dft_control_type), POINTER :: dft_control
1307 : TYPE(mp_para_env_type), POINTER :: para_env
1308 : TYPE(pw_env_type), POINTER :: pw_env
1309 : TYPE(pw_pool_type), POINTER :: pw_pool
1310 : TYPE(pw_r3d_rs_type) :: v_hartree
1311 : TYPE(qs_subsys_type), POINTER :: subsys
1312 :
1313 6 : CALL timeset(routineN, handle)
1314 :
1315 6 : IF (ALLOCATED(negf_control%atomlist_S_screening)) THEN
1316 : CALL get_qs_env(qs_env, &
1317 : dft_control=dft_control, &
1318 : do_kpoints=do_kpoints, &
1319 : matrix_ks_kp=matrix_ks_kp, &
1320 : matrix_s_kp=matrix_s_kp, &
1321 : para_env=para_env, &
1322 : pw_env=pw_env, &
1323 6 : subsys=subsys)
1324 6 : IF (dft_control%qs_control%xtb) CALL rebuild_pw_env(qs_env)
1325 6 : CALL pw_env_get(pw_env, auxbas_pw_pool=pw_pool)
1326 :
1327 6 : IF (do_kpoints) THEN
1328 : CALL cp_abort(__LOCATION__, &
1329 0 : "K-points in device region have not been implemented yet.")
1330 : END IF
1331 :
1332 6 : ncontacts = SIZE(negf_control%contacts)
1333 6 : nspins = dft_control%nspins
1334 :
1335 6 : NULLIFY (fm_struct)
1336 6 : nao_s = number_of_atomic_orbitals(subsys, negf_control%atomlist_S_screening)
1337 :
1338 : ! ++ create matrices: h_s, s_s
1339 6 : NULLIFY (negf_env%s_s, negf_env%v_hartree_s, fm_struct)
1340 24 : ALLOCATE (negf_env%h_s(nspins))
1341 :
1342 6 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao_s, ncol_global=nao_s, context=sub_env%blacs_env)
1343 6 : ALLOCATE (negf_env%s_s)
1344 6 : CALL cp_fm_create(negf_env%s_s, fm_struct)
1345 12 : DO ispin = 1, nspins
1346 12 : CALL cp_fm_create(negf_env%h_s(ispin), fm_struct)
1347 : END DO
1348 6 : ALLOCATE (negf_env%v_hartree_s)
1349 6 : CALL cp_fm_create(negf_env%v_hartree_s, fm_struct)
1350 6 : CALL cp_fm_struct_release(fm_struct)
1351 :
1352 : ! ++ create matrices: h_sc, s_sc
1353 72 : ALLOCATE (negf_env%h_sc(nspins, ncontacts), negf_env%s_sc(ncontacts))
1354 18 : DO icontact = 1, ncontacts
1355 12 : nao_c = number_of_atomic_orbitals(subsys, negf_env%contacts(icontact)%atomlist_cell0)
1356 12 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao_s, ncol_global=nao_c, context=sub_env%blacs_env)
1357 :
1358 12 : CALL cp_fm_create(negf_env%s_sc(icontact), fm_struct)
1359 :
1360 24 : DO ispin = 1, nspins
1361 24 : CALL cp_fm_create(negf_env%h_sc(ispin, icontact), fm_struct)
1362 : END DO
1363 :
1364 18 : CALL cp_fm_struct_release(fm_struct)
1365 : END DO
1366 :
1367 : ! extract matrices: h_s, s_s
1368 12 : DO ispin = 1, nspins
1369 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
1370 : fm=negf_env%h_s(ispin), &
1371 : atomlist_row=negf_control%atomlist_S_screening, &
1372 : atomlist_col=negf_control%atomlist_S_screening, &
1373 : subsys=subsys, mpi_comm_global=para_env, &
1374 12 : do_upper_diag=.TRUE., do_lower=.TRUE.)
1375 : END DO
1376 :
1377 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
1378 : fm=negf_env%s_s, &
1379 : atomlist_row=negf_control%atomlist_S_screening, &
1380 : atomlist_col=negf_control%atomlist_S_screening, &
1381 : subsys=subsys, mpi_comm_global=para_env, &
1382 6 : do_upper_diag=.TRUE., do_lower=.TRUE.)
1383 :
1384 : ! v_hartree_s
1385 6 : NULLIFY (hmat%matrix)
1386 6 : CALL dbcsr_init_p(hmat%matrix)
1387 6 : CALL dbcsr_copy(matrix_b=hmat%matrix, matrix_a=matrix_s_kp(1, 1)%matrix)
1388 6 : CALL dbcsr_set(hmat%matrix, 0.0_dp)
1389 :
1390 6 : CALL pw_pool%create_pw(v_hartree)
1391 6 : CALL negf_env_init_v_hartree(v_hartree, negf_env%contacts, negf_control%contacts)
1392 :
1393 : CALL integrate_v_rspace(v_rspace=v_hartree, hmat=hmat, qs_env=qs_env, &
1394 6 : calculate_forces=.FALSE., compute_tau=.FALSE., gapw=.FALSE.)
1395 :
1396 6 : CALL pw_pool%give_back_pw(v_hartree)
1397 :
1398 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=hmat%matrix, &
1399 : fm=negf_env%v_hartree_s, &
1400 : atomlist_row=negf_control%atomlist_S_screening, &
1401 : atomlist_col=negf_control%atomlist_S_screening, &
1402 : subsys=subsys, mpi_comm_global=para_env, &
1403 6 : do_upper_diag=.TRUE., do_lower=.TRUE.)
1404 :
1405 6 : CALL dbcsr_deallocate_matrix(hmat%matrix)
1406 :
1407 : ! extract matrices: h_sc, s_sc
1408 18 : DO icontact = 1, ncontacts
1409 24 : DO ispin = 1, nspins
1410 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_ks_kp(ispin, 1)%matrix, &
1411 : fm=negf_env%h_sc(ispin, icontact), &
1412 : atomlist_row=negf_control%atomlist_S_screening, &
1413 : atomlist_col=negf_env%contacts(icontact)%atomlist_cell0, &
1414 : subsys=subsys, mpi_comm_global=para_env, &
1415 24 : do_upper_diag=.TRUE., do_lower=.TRUE.)
1416 : END DO
1417 :
1418 : CALL negf_copy_sym_dbcsr_to_fm_submat(matrix=matrix_s_kp(1, 1)%matrix, &
1419 : fm=negf_env%s_sc(icontact), &
1420 : atomlist_row=negf_control%atomlist_S_screening, &
1421 : atomlist_col=negf_env%contacts(icontact)%atomlist_cell0, &
1422 : subsys=subsys, mpi_comm_global=para_env, &
1423 18 : do_upper_diag=.TRUE., do_lower=.TRUE.)
1424 : END DO
1425 : END IF
1426 :
1427 6 : CALL timestop(handle)
1428 6 : END SUBROUTINE negf_env_device_init_matrices
1429 :
1430 : ! **************************************************************************************************
1431 : !> \brief Contribution to the Hartree potential related to the external bias voltage.
1432 : !> \param v_hartree Hartree potential (modified on exit)
1433 : !> \param contact_env NEGF environment for every contact
1434 : !> \param contact_control NEGF control for every contact
1435 : !> \author Sergey Chulkov
1436 : ! **************************************************************************************************
1437 6 : SUBROUTINE negf_env_init_v_hartree(v_hartree, contact_env, contact_control)
1438 : TYPE(pw_r3d_rs_type), INTENT(IN) :: v_hartree
1439 : TYPE(negf_env_contact_type), DIMENSION(:), &
1440 : INTENT(in) :: contact_env
1441 : TYPE(negf_control_contact_type), DIMENSION(:), &
1442 : INTENT(in) :: contact_control
1443 :
1444 : CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_init_v_hartree'
1445 : REAL(kind=dp), PARAMETER :: threshold = 16.0_dp*EPSILON(0.0_dp)
1446 :
1447 : INTEGER :: dx, dy, dz, handle, icontact, ix, iy, &
1448 : iz, lx, ly, lz, ncontacts, ux, uy, uz
1449 : REAL(kind=dp) :: dvol, pot, proj, v1, v2
1450 : REAL(kind=dp), DIMENSION(3) :: dirvector_bias, point_coord, &
1451 : point_indices, vector
1452 :
1453 6 : CALL timeset(routineN, handle)
1454 :
1455 6 : ncontacts = SIZE(contact_env)
1456 6 : CPASSERT(SIZE(contact_control) == ncontacts)
1457 6 : CPASSERT(ncontacts == 2)
1458 :
1459 24 : dirvector_bias = contact_env(2)%origin_bias - contact_env(1)%origin_bias
1460 6 : v1 = contact_control(1)%v_external
1461 6 : v2 = contact_control(2)%v_external
1462 :
1463 6 : lx = v_hartree%pw_grid%bounds_local(1, 1)
1464 6 : ux = v_hartree%pw_grid%bounds_local(2, 1)
1465 6 : ly = v_hartree%pw_grid%bounds_local(1, 2)
1466 6 : uy = v_hartree%pw_grid%bounds_local(2, 2)
1467 6 : lz = v_hartree%pw_grid%bounds_local(1, 3)
1468 6 : uz = v_hartree%pw_grid%bounds_local(2, 3)
1469 :
1470 6 : dx = v_hartree%pw_grid%npts(1)/2
1471 6 : dy = v_hartree%pw_grid%npts(2)/2
1472 6 : dz = v_hartree%pw_grid%npts(3)/2
1473 :
1474 6 : dvol = v_hartree%pw_grid%dvol
1475 :
1476 1910 : DO iz = lz, uz
1477 1904 : point_indices(3) = REAL(iz + dz, kind=dp)
1478 98310 : DO iy = ly, uy
1479 96400 : point_indices(2) = REAL(iy + dy, kind=dp)
1480 :
1481 2663864 : DO ix = lx, ux
1482 2565560 : point_indices(1) = REAL(ix + dx, kind=dp)
1483 33352280 : point_coord(:) = MATMUL(v_hartree%pw_grid%dh, point_indices)
1484 :
1485 10262240 : vector = point_coord - contact_env(1)%origin_bias
1486 2565560 : proj = projection_on_direction_vector(vector, dirvector_bias)
1487 2565560 : IF (proj + threshold >= 0.0_dp .AND. proj - threshold <= 1.0_dp) THEN
1488 : ! scattering region
1489 : ! proj == 0 we are at the first contact boundary
1490 : ! proj == 1 we are at the second contact boundary
1491 1006637 : IF (proj < 0.0_dp) THEN
1492 : proj = 0.0_dp
1493 : ELSE IF (proj > 1.0_dp) THEN
1494 : proj = 1.0_dp
1495 : END IF
1496 1006637 : pot = v1 + (v2 - v1)*proj
1497 : ELSE
1498 2469287 : pot = 0.0_dp
1499 2469287 : DO icontact = 1, ncontacts
1500 9523808 : vector = point_coord - contact_env(icontact)%origin_bias
1501 2380952 : proj = projection_on_direction_vector(vector, contact_env(icontact)%direction_vector_bias)
1502 :
1503 2469287 : IF (proj + threshold >= 0.0_dp .AND. proj - threshold <= 1.0_dp) THEN
1504 1470588 : pot = contact_control(icontact)%v_external
1505 1470588 : EXIT
1506 : END IF
1507 : END DO
1508 : END IF
1509 :
1510 2661960 : v_hartree%array(ix, iy, iz) = pot*dvol
1511 : END DO
1512 : END DO
1513 : END DO
1514 :
1515 6 : CALL timestop(handle)
1516 6 : END SUBROUTINE negf_env_init_v_hartree
1517 :
1518 : ! **************************************************************************************************
1519 : !> \brief Detect the axis towards secondary unit cell.
1520 : !> \param direction_vector direction vector
1521 : !> \param subsys_contact QuickStep subsystem of the contact force environment
1522 : !> \param eps_geometry accuracy in mapping atoms between different force environments
1523 : !> \return direction axis: 0 (undefined), 1 (x), 2(y), 3 (z)
1524 : !> \par History
1525 : !> * 08.2017 created [Sergey Chulkov]
1526 : ! **************************************************************************************************
1527 12 : FUNCTION contact_direction_axis(direction_vector, subsys_contact, eps_geometry) RESULT(direction_axis)
1528 : REAL(kind=dp), DIMENSION(3), INTENT(in) :: direction_vector
1529 : TYPE(qs_subsys_type), POINTER :: subsys_contact
1530 : REAL(kind=dp), INTENT(in) :: eps_geometry
1531 : INTEGER :: direction_axis
1532 :
1533 : INTEGER :: i, naxes
1534 : REAL(kind=dp), DIMENSION(3) :: scaled
1535 : TYPE(cell_type), POINTER :: cell
1536 :
1537 12 : CALL qs_subsys_get(subsys_contact, cell=cell)
1538 12 : CALL real_to_scaled(scaled, direction_vector, cell)
1539 :
1540 12 : naxes = 0
1541 12 : direction_axis = 0 ! initialize to make GCC<=6 happy
1542 :
1543 48 : DO i = 1, 3
1544 48 : IF (ABS(scaled(i)) > eps_geometry) THEN
1545 12 : IF (scaled(i) > 0.0_dp) THEN
1546 : direction_axis = i
1547 : ELSE
1548 6 : direction_axis = -i
1549 : END IF
1550 12 : naxes = naxes + 1
1551 : END IF
1552 : END DO
1553 :
1554 : ! direction_vector is not parallel to one of the unit cell's axis
1555 12 : IF (naxes /= 1) direction_axis = 0
1556 12 : END FUNCTION contact_direction_axis
1557 :
1558 : ! **************************************************************************************************
1559 : !> \brief Estimate energy of the highest spin-alpha occupied molecular orbital.
1560 : !> \param homo_energy HOMO energy (initialised on exit)
1561 : !> \param qs_env QuickStep environment
1562 : !> \par History
1563 : !> * 01.2017 created [Sergey Chulkov]
1564 : ! **************************************************************************************************
1565 4 : SUBROUTINE negf_homo_energy_estimate(homo_energy, qs_env)
1566 : REAL(kind=dp), INTENT(out) :: homo_energy
1567 : TYPE(qs_environment_type), POINTER :: qs_env
1568 :
1569 : CHARACTER(LEN=*), PARAMETER :: routineN = 'negf_homo_energy_estimate'
1570 : INTEGER, PARAMETER :: gamma_point = 1
1571 :
1572 : INTEGER :: handle, homo, ikpgr, ikpoint, imo, &
1573 : ispin, kplocal, nmo, nspins
1574 : INTEGER, DIMENSION(2) :: kp_range
1575 : LOGICAL :: do_kpoints
1576 : REAL(kind=dp) :: my_homo_energy
1577 4 : REAL(kind=dp), DIMENSION(:), POINTER :: eigenvalues
1578 4 : TYPE(kpoint_env_p_type), DIMENSION(:), POINTER :: kp_env
1579 : TYPE(kpoint_type), POINTER :: kpoints
1580 4 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
1581 4 : TYPE(mo_set_type), DIMENSION(:, :), POINTER :: mos_kp
1582 : TYPE(mp_para_env_type), POINTER :: para_env, para_env_kp
1583 :
1584 4 : CALL timeset(routineN, handle)
1585 4 : my_homo_energy = 0.0_dp
1586 :
1587 4 : CALL get_qs_env(qs_env, para_env=para_env, mos=mos, kpoints=kpoints, do_kpoints=do_kpoints)
1588 :
1589 4 : IF (do_kpoints) THEN
1590 4 : CALL get_kpoint_info(kpoints, kp_env=kp_env, kp_range=kp_range, para_env_kp=para_env_kp)
1591 :
1592 : ! looking for a processor that holds the gamma point
1593 4 : IF (para_env_kp%mepos == 0 .AND. kp_range(1) <= gamma_point .AND. kp_range(2) >= gamma_point) THEN
1594 2 : kplocal = kp_range(2) - kp_range(1) + 1
1595 :
1596 2 : DO ikpgr = 1, kplocal
1597 2 : CALL get_kpoint_env(kp_env(ikpgr)%kpoint_env, nkpoint=ikpoint, mos=mos_kp)
1598 :
1599 2 : IF (ikpoint == gamma_point) THEN
1600 : ! mos_kp(component, spin), where component = 1 (real), or 2 (imaginary)
1601 2 : CALL get_mo_set(mos_kp(1, 1), homo=homo, eigenvalues=eigenvalues) ! mu=fermi_level
1602 :
1603 2 : my_homo_energy = eigenvalues(homo)
1604 2 : EXIT
1605 : END IF
1606 : END DO
1607 : END IF
1608 :
1609 4 : CALL para_env%sum(my_homo_energy)
1610 : ELSE
1611 : ! Hamiltonian of the bulk contact region has been computed without k-points.
1612 : ! Try to obtain the HOMO energy assuming there is no OT. We probably should abort here
1613 : ! as we do need a second replica of the bulk contact unit cell along transport
1614 : ! direction anyway which is not available without k-points.
1615 :
1616 : CALL cp_abort(__LOCATION__, &
1617 : "It is necessary to use k-points along the transport direction "// &
1618 0 : "for all contact FORCE_EVAL-s")
1619 : ! It is necessary to use k-points along the transport direction within all contact FORCE_EVAL-s
1620 :
1621 0 : nspins = SIZE(mos)
1622 :
1623 0 : spin_loop: DO ispin = 1, nspins
1624 0 : CALL get_mo_set(mos(ispin), homo=homo, nmo=nmo, eigenvalues=eigenvalues)
1625 :
1626 0 : DO imo = nmo, 1, -1
1627 0 : IF (eigenvalues(imo) /= 0.0_dp) EXIT spin_loop
1628 : END DO
1629 : END DO spin_loop
1630 :
1631 0 : IF (imo == 0) THEN
1632 0 : CPABORT("Orbital transformation (OT) for contact FORCE_EVAL-s is not supported")
1633 : END IF
1634 :
1635 0 : my_homo_energy = eigenvalues(homo)
1636 : END IF
1637 :
1638 4 : homo_energy = my_homo_energy
1639 4 : CALL timestop(handle)
1640 4 : END SUBROUTINE negf_homo_energy_estimate
1641 :
1642 : ! **************************************************************************************************
1643 : !> \brief List atoms from the contact's primary unit cell.
1644 : !> \param atomlist_cell0 list of atoms belonging to the contact's primary unit cell
1645 : !> (allocate and initialised on exit)
1646 : !> \param atom_map_cell0 atomic map of atoms from 'atomlist_cell0' (allocate and initialised on exit)
1647 : !> \param atomlist_bulk list of atoms belonging to the bulk contact region
1648 : !> \param atom_map atomic map of atoms from 'atomlist_bulk'
1649 : !> \param origin origin of the contact
1650 : !> \param direction_vector direction vector of the contact
1651 : !> \param direction_axis axis towards secondary unit cell
1652 : !> \param subsys_device QuickStep subsystem of the device force environment
1653 : !> \par History
1654 : !> * 08.2017 created [Sergey Chulkov]
1655 : ! **************************************************************************************************
1656 4 : SUBROUTINE list_atoms_in_bulk_primary_unit_cell(atomlist_cell0, atom_map_cell0, atomlist_bulk, atom_map, &
1657 : origin, direction_vector, direction_axis, subsys_device)
1658 : INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(inout) :: atomlist_cell0
1659 : TYPE(negf_atom_map_type), ALLOCATABLE, &
1660 : DIMENSION(:), INTENT(inout) :: atom_map_cell0
1661 : INTEGER, DIMENSION(:), INTENT(in) :: atomlist_bulk
1662 : TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
1663 : REAL(kind=dp), DIMENSION(3), INTENT(in) :: origin, direction_vector
1664 : INTEGER, INTENT(in) :: direction_axis
1665 : TYPE(qs_subsys_type), POINTER :: subsys_device
1666 :
1667 : CHARACTER(LEN=*), PARAMETER :: routineN = 'list_atoms_in_bulk_primary_unit_cell'
1668 :
1669 : INTEGER :: atom_min, dir_axis_min, &
1670 : direction_axis_abs, handle, iatom, &
1671 : natoms_bulk, natoms_cell0
1672 : REAL(kind=dp) :: proj, proj_min
1673 : REAL(kind=dp), DIMENSION(3) :: vector
1674 4 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1675 :
1676 4 : CALL timeset(routineN, handle)
1677 4 : CALL qs_subsys_get(subsys_device, particle_set=particle_set)
1678 :
1679 4 : natoms_bulk = SIZE(atomlist_bulk)
1680 4 : CPASSERT(SIZE(atom_map, 1) == natoms_bulk)
1681 4 : direction_axis_abs = ABS(direction_axis)
1682 :
1683 : ! looking for the nearest atom from the scattering region
1684 4 : proj_min = 1.0_dp
1685 4 : atom_min = 1
1686 36 : DO iatom = 1, natoms_bulk
1687 128 : vector = particle_set(atomlist_bulk(iatom))%r - origin
1688 32 : proj = projection_on_direction_vector(vector, direction_vector)
1689 :
1690 36 : IF (proj < proj_min) THEN
1691 16 : proj_min = proj
1692 16 : atom_min = iatom
1693 : END IF
1694 : END DO
1695 :
1696 4 : dir_axis_min = atom_map(atom_min)%cell(direction_axis_abs)
1697 :
1698 4 : natoms_cell0 = 0
1699 36 : DO iatom = 1, natoms_bulk
1700 36 : IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min) THEN
1701 16 : natoms_cell0 = natoms_cell0 + 1
1702 : END IF
1703 : END DO
1704 :
1705 12 : ALLOCATE (atomlist_cell0(natoms_cell0))
1706 40 : ALLOCATE (atom_map_cell0(natoms_cell0))
1707 :
1708 4 : natoms_cell0 = 0
1709 36 : DO iatom = 1, natoms_bulk
1710 36 : IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min) THEN
1711 16 : natoms_cell0 = natoms_cell0 + 1
1712 16 : atomlist_cell0(natoms_cell0) = atomlist_bulk(iatom)
1713 16 : atom_map_cell0(natoms_cell0) = atom_map(iatom)
1714 : END IF
1715 : END DO
1716 :
1717 4 : CALL timestop(handle)
1718 4 : END SUBROUTINE list_atoms_in_bulk_primary_unit_cell
1719 :
1720 : ! **************************************************************************************************
1721 : !> \brief List atoms from the contact's secondary unit cell.
1722 : !> \param atomlist_cell1 list of atoms belonging to the contact's secondary unit cell
1723 : !> (allocate and initialised on exit)
1724 : !> \param atom_map_cell1 atomic map of atoms from 'atomlist_cell1'
1725 : !> (allocate and initialised on exit)
1726 : !> \param atomlist_bulk list of atoms belonging to the bulk contact region
1727 : !> \param atom_map atomic map of atoms from 'atomlist_bulk'
1728 : !> \param origin origin of the contact
1729 : !> \param direction_vector direction vector of the contact
1730 : !> \param direction_axis axis towards the secondary unit cell
1731 : !> \param subsys_device QuickStep subsystem of the device force environment
1732 : !> \par History
1733 : !> * 11.2017 created [Sergey Chulkov]
1734 : !> \note Cloned from list_atoms_in_bulk_primary_unit_cell. Will be removed once we can managed to
1735 : !> maintain consistency between real-space matrices from different force_eval sections.
1736 : ! **************************************************************************************************
1737 4 : SUBROUTINE list_atoms_in_bulk_secondary_unit_cell(atomlist_cell1, atom_map_cell1, atomlist_bulk, atom_map, &
1738 : origin, direction_vector, direction_axis, subsys_device)
1739 : INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(inout) :: atomlist_cell1
1740 : TYPE(negf_atom_map_type), ALLOCATABLE, &
1741 : DIMENSION(:), INTENT(inout) :: atom_map_cell1
1742 : INTEGER, DIMENSION(:), INTENT(in) :: atomlist_bulk
1743 : TYPE(negf_atom_map_type), DIMENSION(:), INTENT(in) :: atom_map
1744 : REAL(kind=dp), DIMENSION(3), INTENT(in) :: origin, direction_vector
1745 : INTEGER, INTENT(in) :: direction_axis
1746 : TYPE(qs_subsys_type), POINTER :: subsys_device
1747 :
1748 : CHARACTER(LEN=*), PARAMETER :: routineN = 'list_atoms_in_bulk_secondary_unit_cell'
1749 :
1750 : INTEGER :: atom_min, dir_axis_min, &
1751 : direction_axis_abs, handle, iatom, &
1752 : natoms_bulk, natoms_cell1, offset
1753 : REAL(kind=dp) :: proj, proj_min
1754 : REAL(kind=dp), DIMENSION(3) :: vector
1755 4 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1756 :
1757 4 : CALL timeset(routineN, handle)
1758 4 : CALL qs_subsys_get(subsys_device, particle_set=particle_set)
1759 :
1760 4 : natoms_bulk = SIZE(atomlist_bulk)
1761 4 : CPASSERT(SIZE(atom_map, 1) == natoms_bulk)
1762 4 : direction_axis_abs = ABS(direction_axis)
1763 4 : offset = SIGN(1, direction_axis)
1764 :
1765 : ! looking for the nearest atom from the scattering region
1766 4 : proj_min = 1.0_dp
1767 4 : atom_min = 1
1768 36 : DO iatom = 1, natoms_bulk
1769 128 : vector = particle_set(atomlist_bulk(iatom))%r - origin
1770 32 : proj = projection_on_direction_vector(vector, direction_vector)
1771 :
1772 36 : IF (proj < proj_min) THEN
1773 16 : proj_min = proj
1774 16 : atom_min = iatom
1775 : END IF
1776 : END DO
1777 :
1778 4 : dir_axis_min = atom_map(atom_min)%cell(direction_axis_abs)
1779 :
1780 4 : natoms_cell1 = 0
1781 36 : DO iatom = 1, natoms_bulk
1782 36 : IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min + offset) THEN
1783 16 : natoms_cell1 = natoms_cell1 + 1
1784 : END IF
1785 : END DO
1786 :
1787 12 : ALLOCATE (atomlist_cell1(natoms_cell1))
1788 40 : ALLOCATE (atom_map_cell1(natoms_cell1))
1789 :
1790 4 : natoms_cell1 = 0
1791 36 : DO iatom = 1, natoms_bulk
1792 36 : IF (atom_map(iatom)%cell(direction_axis_abs) == dir_axis_min + offset) THEN
1793 16 : natoms_cell1 = natoms_cell1 + 1
1794 16 : atomlist_cell1(natoms_cell1) = atomlist_bulk(iatom)
1795 16 : atom_map_cell1(natoms_cell1) = atom_map(iatom)
1796 16 : atom_map_cell1(natoms_cell1)%cell(direction_axis_abs) = dir_axis_min
1797 : END IF
1798 : END DO
1799 :
1800 4 : CALL timestop(handle)
1801 4 : END SUBROUTINE list_atoms_in_bulk_secondary_unit_cell
1802 :
1803 : ! **************************************************************************************************
1804 : !> \brief Release a NEGF environment variable.
1805 : !> \param negf_env NEGF environment to release
1806 : !> \par History
1807 : !> * 01.2017 created [Sergey Chulkov]
1808 : ! **************************************************************************************************
1809 6 : SUBROUTINE negf_env_release(negf_env)
1810 : TYPE(negf_env_type), INTENT(inout) :: negf_env
1811 :
1812 : CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_release'
1813 :
1814 : INTEGER :: handle, icontact
1815 :
1816 6 : CALL timeset(routineN, handle)
1817 :
1818 6 : IF (ALLOCATED(negf_env%contacts)) THEN
1819 18 : DO icontact = SIZE(negf_env%contacts), 1, -1
1820 18 : CALL negf_env_contact_release(negf_env%contacts(icontact))
1821 : END DO
1822 :
1823 18 : DEALLOCATE (negf_env%contacts)
1824 : END IF
1825 :
1826 : ! h_s
1827 6 : CALL cp_fm_release(negf_env%h_s)
1828 :
1829 : ! h_sc
1830 6 : CALL cp_fm_release(negf_env%h_sc)
1831 :
1832 : ! s_s
1833 6 : IF (ASSOCIATED(negf_env%s_s)) THEN
1834 6 : CALL cp_fm_release(negf_env%s_s)
1835 6 : DEALLOCATE (negf_env%s_s)
1836 : NULLIFY (negf_env%s_s)
1837 : END IF
1838 :
1839 : ! s_sc
1840 6 : CALL cp_fm_release(negf_env%s_sc)
1841 :
1842 : ! v_hartree_s
1843 6 : IF (ASSOCIATED(negf_env%v_hartree_s)) THEN
1844 6 : CALL cp_fm_release(negf_env%v_hartree_s)
1845 6 : DEALLOCATE (negf_env%v_hartree_s)
1846 : NULLIFY (negf_env%v_hartree_s)
1847 : END IF
1848 :
1849 : ! density mixing
1850 6 : IF (ASSOCIATED(negf_env%mixing_storage)) THEN
1851 6 : CALL mixing_storage_release(negf_env%mixing_storage)
1852 6 : DEALLOCATE (negf_env%mixing_storage)
1853 : END IF
1854 :
1855 6 : CALL timestop(handle)
1856 6 : END SUBROUTINE negf_env_release
1857 :
1858 : ! **************************************************************************************************
1859 : !> \brief Release a NEGF contact environment variable.
1860 : !> \param contact_env NEGF contact environment to release
1861 : ! **************************************************************************************************
1862 12 : SUBROUTINE negf_env_contact_release(contact_env)
1863 : TYPE(negf_env_contact_type), INTENT(inout) :: contact_env
1864 :
1865 : CHARACTER(len=*), PARAMETER :: routineN = 'negf_env_contact_release'
1866 :
1867 : INTEGER :: handle
1868 :
1869 12 : CALL timeset(routineN, handle)
1870 :
1871 : ! h_00
1872 12 : CALL cp_fm_release(contact_env%h_00)
1873 :
1874 : ! h_01
1875 12 : CALL cp_fm_release(contact_env%h_01)
1876 :
1877 : ! rho_00
1878 12 : CALL cp_fm_release(contact_env%rho_00)
1879 :
1880 : ! rho_01
1881 12 : CALL cp_fm_release(contact_env%rho_01)
1882 :
1883 : ! s_00
1884 12 : IF (ASSOCIATED(contact_env%s_00)) THEN
1885 12 : CALL cp_fm_release(contact_env%s_00)
1886 12 : DEALLOCATE (contact_env%s_00)
1887 : NULLIFY (contact_env%s_00)
1888 : END IF
1889 :
1890 : ! s_01
1891 12 : IF (ASSOCIATED(contact_env%s_01)) THEN
1892 12 : CALL cp_fm_release(contact_env%s_01)
1893 12 : DEALLOCATE (contact_env%s_01)
1894 : NULLIFY (contact_env%s_01)
1895 : END IF
1896 :
1897 12 : IF (ALLOCATED(contact_env%atomlist_cell0)) DEALLOCATE (contact_env%atomlist_cell0)
1898 12 : IF (ALLOCATED(contact_env%atomlist_cell1)) DEALLOCATE (contact_env%atomlist_cell1)
1899 12 : IF (ALLOCATED(contact_env%atom_map_cell0)) DEALLOCATE (contact_env%atom_map_cell0)
1900 :
1901 12 : CALL timestop(handle)
1902 12 : END SUBROUTINE negf_env_contact_release
1903 :
1904 0 : END MODULE negf_env_types
|