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 Routines for reading and writing NEGF restart files.
10 : !> \author Dmitry Ryndyk (12.2025)
11 : ! **************************************************************************************************
12 : MODULE negf_io
13 :
14 : USE cp_files, ONLY: close_file,&
15 : open_file
16 : USE cp_log_handling, ONLY: cp_logger_generate_filename,&
17 : cp_logger_type
18 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
19 : section_vals_type,&
20 : section_vals_val_get
21 : USE kinds, ONLY: default_path_length,&
22 : default_string_length,&
23 : dp
24 : #include "./base/base_uses.f90"
25 :
26 : IMPLICIT NONE
27 :
28 : PRIVATE
29 :
30 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_io'
31 :
32 : PUBLIC :: negf_restart_file_name, &
33 : negf_print_matrix_to_file, &
34 : negf_read_matrix_from_file
35 :
36 : CONTAINS
37 :
38 : ! **************************************************************************************************
39 : !> \brief Checks if the restart file exists and returns the filename.
40 : !> \param filename ...
41 : !> \param exist ...
42 : !> \param negf_section ...
43 : !> \param logger ...
44 : !> \param icontact ...
45 : !> \param ispin ...
46 : !> \param h00 ...
47 : !> \param h01 ...
48 : !> \param s00 ...
49 : !> \param s01 ...
50 : !> \par History
51 : !> * 12.2025 created [Dmitry Ryndyk]
52 : ! **************************************************************************************************
53 0 : SUBROUTINE negf_restart_file_name(filename, exist, negf_section, logger, icontact, ispin, h00, h01, s00, s01)
54 : CHARACTER(LEN=default_path_length), INTENT(OUT) :: filename
55 : LOGICAL, INTENT(OUT) :: exist
56 : TYPE(section_vals_type), POINTER :: negf_section
57 : TYPE(cp_logger_type), POINTER :: logger
58 : INTEGER, INTENT(IN), OPTIONAL :: icontact, ispin
59 : LOGICAL, INTENT(IN), OPTIONAL :: h00, h01, s00, s01
60 :
61 : CHARACTER(len=default_string_length) :: middle_name, string1, string2
62 : LOGICAL :: my_h00, my_h01, my_s00, my_s01
63 : TYPE(section_vals_type), POINTER :: contact_section, print_key
64 :
65 0 : my_h00 = .FALSE.
66 0 : IF (PRESENT(h00)) my_h00 = h00
67 0 : my_h01 = .FALSE.
68 0 : IF (PRESENT(h01)) my_h01 = h01
69 0 : my_s00 = .FALSE.
70 0 : IF (PRESENT(s00)) my_s00 = s00
71 0 : my_s01 = .FALSE.
72 0 : IF (PRESENT(s01)) my_s01 = s01
73 :
74 0 : exist = .FALSE.
75 :
76 : ! try to read from the filename that is generated automatically from the printkey
77 0 : contact_section => section_vals_get_subs_vals(negf_section, "CONTACT")
78 0 : print_key => section_vals_get_subs_vals(contact_section, "RESTART", i_rep_section=icontact)
79 :
80 0 : IF (my_h00) THEN
81 :
82 0 : WRITE (string1, *) icontact
83 0 : WRITE (string2, *) ispin
84 0 : IF (ispin == 0) THEN
85 0 : middle_name = "N"//TRIM(string1)//"-H00"
86 : ELSE
87 0 : middle_name = "N"//TRIM(string1)//"-H00-S"//TRIM(string2)
88 : END IF
89 : filename = negf_elecrodes_generate_filename(logger, print_key, middle_name=middle_name, &
90 0 : extension=".hs", my_local=.FALSE.)
91 : END IF
92 :
93 0 : IF (my_h01) THEN
94 0 : WRITE (string1, *) icontact
95 0 : WRITE (string2, *) ispin
96 0 : IF (ispin == 0) THEN
97 0 : middle_name = "N"//TRIM(string1)//"-H01"
98 : ELSE
99 0 : middle_name = "N"//TRIM(string1)//"-H01-S"//TRIM(string2)
100 : END IF
101 : filename = negf_elecrodes_generate_filename(logger, print_key, middle_name=middle_name, &
102 0 : extension=".hs", my_local=.FALSE.)
103 : END IF
104 :
105 0 : IF (my_s00) THEN
106 0 : WRITE (string1, *) icontact
107 0 : middle_name = "N"//TRIM(string1)//"-S00"
108 : filename = negf_elecrodes_generate_filename(logger, print_key, middle_name=middle_name, &
109 0 : extension=".hs", my_local=.FALSE.)
110 : END IF
111 :
112 0 : IF (my_s01) THEN
113 0 : WRITE (string1, *) icontact
114 0 : middle_name = "N"//TRIM(string1)//"-S01"
115 : filename = negf_elecrodes_generate_filename(logger, print_key, middle_name=middle_name, &
116 0 : extension=".hs", my_local=.FALSE.)
117 : END IF
118 :
119 0 : INQUIRE (FILE=filename, exist=exist)
120 :
121 0 : END SUBROUTINE negf_restart_file_name
122 :
123 : ! **************************************************************************************************
124 : !> \brief ...
125 : !> \param logger the logger for the parallel environment, iteration info
126 : !> and filename generation
127 : !> \param print_key ...
128 : !> \param middle_name name to be added to the generated filename, useful when
129 : !> print_key activates different distinct outputs, to be able to
130 : !> distinguish them
131 : !> \param extension extension to be applied to the filename (including the ".")
132 : !> \param my_local if the unit should be local to this task, or global to the
133 : !> program (defaults to false).
134 : !> \return ...
135 : !> \par History
136 : !> * 12.2025 created [Dmitry Ryndyk]
137 : ! **************************************************************************************************
138 0 : FUNCTION negf_elecrodes_generate_filename(logger, print_key, middle_name, extension, &
139 : my_local) RESULT(filename)
140 : TYPE(cp_logger_type), POINTER :: logger
141 : TYPE(section_vals_type), POINTER :: print_key
142 : CHARACTER(len=*), INTENT(IN), OPTIONAL :: middle_name
143 : CHARACTER(len=*), INTENT(IN) :: extension
144 : LOGICAL, INTENT(IN) :: my_local
145 : CHARACTER(len=default_path_length) :: filename
146 :
147 : CHARACTER(len=default_path_length) :: outName, outPath, postfix, root
148 : CHARACTER(len=default_string_length) :: my_middle_name
149 : INTEGER :: my_ind1, my_ind2
150 : LOGICAL :: has_root
151 :
152 0 : CALL section_vals_val_get(print_key, "FILENAME", c_val=outPath)
153 0 : IF (outPath(1:1) == '=') THEN
154 : CPASSERT(LEN(outPath) - 1 <= LEN(filename))
155 0 : filename = outPath(2:)
156 0 : RETURN
157 : END IF
158 0 : IF (outPath == "__STD_OUT__") outPath = ""
159 0 : outName = outPath
160 0 : has_root = .FALSE.
161 0 : my_ind1 = INDEX(outPath, "/")
162 0 : my_ind2 = LEN_TRIM(outPath)
163 0 : IF (my_ind1 /= 0) THEN
164 0 : has_root = .TRUE.
165 0 : DO WHILE (INDEX(outPath(my_ind1 + 1:my_ind2), "/") /= 0)
166 0 : my_ind1 = INDEX(outPath(my_ind1 + 1:my_ind2), "/") + my_ind1
167 : END DO
168 0 : IF (my_ind1 == my_ind2) THEN
169 0 : outName = ""
170 : ELSE
171 0 : outName = outPath(my_ind1 + 1:my_ind2)
172 : END IF
173 : END IF
174 :
175 0 : IF (PRESENT(middle_name)) THEN
176 0 : IF (outName /= "") THEN
177 0 : my_middle_name = "-"//TRIM(outName)//"-"//middle_name
178 : ELSE
179 0 : my_middle_name = "-"//middle_name
180 : END IF
181 : ELSE
182 0 : IF (outName /= "") THEN
183 0 : my_middle_name = "-"//TRIM(outName)
184 : ELSE
185 0 : my_middle_name = ""
186 : END IF
187 : END IF
188 :
189 0 : IF (.NOT. has_root) THEN
190 0 : root = TRIM(logger%iter_info%project_name)//TRIM(my_middle_name)
191 0 : ELSE IF (outName == "") THEN
192 0 : root = outPath(1:my_ind1)//TRIM(logger%iter_info%project_name)//TRIM(my_middle_name)
193 : ELSE
194 0 : root = outPath(1:my_ind1)//my_middle_name(2:LEN_TRIM(my_middle_name))
195 : END IF
196 :
197 0 : postfix = extension
198 :
199 : ! and let the logger generate the filename
200 : CALL cp_logger_generate_filename(logger, res=filename, &
201 0 : root=root, postfix=postfix, local=my_local)
202 :
203 0 : END FUNCTION negf_elecrodes_generate_filename
204 :
205 : ! **************************************************************************************************
206 : !> \brief Prints full matrix to a file.
207 : !> \param filename ...
208 : !> \param matrix ...
209 : !> \par History
210 : !> * 12.2025 created [Dmitry Ryndyk]
211 : ! **************************************************************************************************
212 0 : SUBROUTINE negf_print_matrix_to_file(filename, matrix)
213 : CHARACTER(LEN=default_path_length), INTENT(IN) :: filename
214 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: matrix
215 :
216 : CHARACTER(len=100) :: sfmt
217 : INTEGER :: i, j, ncol, nrow, print_unit
218 :
219 : CALL open_file(file_name=filename, file_status="REPLACE", &
220 : file_form="FORMATTED", file_action="WRITE", &
221 0 : file_position="REWIND", unit_number=print_unit)
222 :
223 0 : nrow = SIZE(matrix, 1)
224 0 : ncol = SIZE(matrix, 2)
225 0 : WRITE (sfmt, "('(',i0,'(E15.5))')") ncol
226 0 : WRITE (print_unit, *) nrow, ncol
227 0 : DO i = 1, nrow
228 0 : WRITE (print_unit, sfmt) (matrix(i, j), j=1, ncol)
229 : END DO
230 :
231 0 : CALL close_file(print_unit)
232 :
233 0 : END SUBROUTINE negf_print_matrix_to_file
234 :
235 : ! **************************************************************************************************
236 : !> \brief Reads full matrix from a file.
237 : !> \param filename ...
238 : !> \param matrix ...
239 : !> \par History
240 : !> * 12.2025 created [Dmitry Ryndyk]
241 : ! **************************************************************************************************
242 0 : SUBROUTINE negf_read_matrix_from_file(filename, matrix)
243 : CHARACTER(LEN=default_path_length), INTENT(IN) :: filename
244 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: matrix
245 :
246 : INTEGER :: i, j, ncol, nrow, print_unit
247 :
248 : CALL open_file(file_name=filename, file_status="OLD", &
249 : file_form="FORMATTED", file_action="READ", &
250 0 : file_position="REWIND", unit_number=print_unit)
251 :
252 0 : READ (print_unit, *) nrow, ncol
253 0 : DO i = 1, nrow
254 0 : READ (print_unit, *) (matrix(i, j), j=1, ncol)
255 : END DO
256 :
257 0 : CALL close_file(print_unit)
258 :
259 0 : END SUBROUTINE negf_read_matrix_from_file
260 :
261 : END MODULE negf_io
|