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 Main program of CP2K
10 : !> \par Copyright
11 : !> CP2K: A general program to perform molecular dynamics simulations
12 : !> Copyright (C) 2000, 2001, 2002, 2003 CP2K developers group
13 : !> Copyright (C) 2004, 2005, 2006, 2007 CP2K developers group
14 : !> Copyright (C) 2008, 2009, 2010, 2011 CP2K developers group
15 : !> Copyright (C) 2012, 2013, 2014, 2015 CP2K developers group
16 : !> Copyright (C) 2016 CP2K developers group
17 : !> \par
18 : !> This program is free software; you can redistribute it and/or modify
19 : !> it under the terms of the GNU General Public License as published by
20 : !> the Free Software Foundation; either version 2 of the License, or
21 : !> (at your option) any later version.
22 : !> \par
23 : !> This program is distributed in the hope that it will be useful,
24 : !> but WITHOUT ANY WARRANTY; without even the implied warranty of
25 : !> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 : !> GNU General Public License for more details.
27 : !> \par
28 : !> You should have received a copy of the GNU General Public License
29 : !> along with this program; if not, write to the Free Software
30 : !> Foundation, Inc., 51 Franklin Street, Fifth Floor,
31 : !> Boston, MA 02110-1301, USA.
32 : !> \par
33 : !> See also https://www.fsf.org/licensing/licenses/gpl.html
34 : !> \par
35 : !> CP2K, including its sources and pointers to the authors
36 : !> can be found at https://docker.axuan.wang/cp2k/
37 : !> \note
38 : !> should be kept as lean as possible.
39 : !> see cp2k_run for more comments
40 : !> \author Joost VandeVondele
41 : ! **************************************************************************************************
42 10338 : PROGRAM cp2k
43 :
44 10338 : USE OMP_LIB, ONLY: omp_get_max_threads,&
45 : omp_set_num_threads
46 : USE cp2k_info, ONLY: compile_revision,&
47 : cp2k_flags,&
48 : cp2k_version,&
49 : print_cp2k_license
50 : USE cp2k_runs, ONLY: run_input,&
51 : write_xml_file
52 : USE cp2k_shell, ONLY: launch_cp2k_shell
53 : USE cp_files, ONLY: open_file
54 : USE f77_interface, ONLY: check_input,&
55 : default_para_env,&
56 : finalize_cp2k,&
57 : init_cp2k
58 : USE input_cp2k, ONLY: create_cp2k_root_section
59 : USE input_section_types, ONLY: section_release,&
60 : section_type
61 : USE iso_fortran_env, ONLY: compiler_options,&
62 : compiler_version
63 : USE kinds, ONLY: default_path_length
64 : USE machine, ONLY: default_output_unit
65 : #include "../base/base_uses.f90"
66 :
67 : IMPLICIT NONE
68 :
69 : CHARACTER(LEN=default_path_length) :: input_file_name, output_file_name, &
70 : arg_att, command
71 : CHARACTER(LEN=default_path_length), &
72 10338 : DIMENSION(:, :), ALLOCATABLE :: initial_variables, initial_variables_tmp
73 10338 : CHARACTER(LEN=:), ALLOCATABLE :: compiler_options_string
74 : INTEGER :: output_unit, l, i, var_set_sep, inp_var_idx
75 : INTEGER :: ierr, i_arg
76 : LOGICAL :: check, usage, echo_input, command_line_error
77 : LOGICAL :: run_it, force_run, has_input, xml, print_version, print_license, shell_mode
78 : TYPE(section_type), POINTER :: input_declaration
79 :
80 10338 : NULLIFY (input_declaration)
81 :
82 : ! output goes to the screen by default
83 10338 : output_unit = default_output_unit
84 :
85 : ! set default behaviour for the command line switches
86 10338 : check = .FALSE.
87 10338 : usage = .FALSE.
88 10338 : echo_input = .FALSE.
89 10338 : has_input = .FALSE.
90 10338 : run_it = .TRUE.
91 10338 : shell_mode = .FALSE.
92 10338 : force_run = .FALSE.
93 10338 : print_version = .FALSE.
94 10338 : print_license = .FALSE.
95 10338 : command_line_error = .FALSE.
96 10338 : xml = .FALSE.
97 10338 : input_file_name = "Missing input file name" ! no default
98 10338 : output_file_name = "__STD_OUT__" ! by default we go to std_out
99 10338 : ALLOCATE (initial_variables(2, 1:0))
100 :
101 : ! Get command and strip path
102 10338 : CALL GET_COMMAND_ARGUMENT(NUMBER=0, VALUE=command, STATUS=ierr)
103 10338 : CPASSERT(ierr == 0)
104 10338 : l = LEN_TRIM(command)
105 103380 : DO i = l, 1, -1
106 103380 : IF (command(i:i) == "/" .OR. command(i:i) == "\") EXIT
107 : END DO
108 10338 : command = command(i + 1:l)
109 :
110 : ! Consider output redirection
111 10338 : i_arg = 0
112 20676 : DO WHILE (i_arg < COMMAND_ARGUMENT_COUNT())
113 10338 : i_arg = i_arg + 1
114 10338 : CALL GET_COMMAND_ARGUMENT(NUMBER=i_arg, VALUE=arg_att, STATUS=ierr)
115 10338 : CPASSERT(ierr == 0)
116 10338 : SELECT CASE (arg_att)
117 : CASE ("-o")
118 10338 : IF (output_file_name == "__STD_OUT__") THEN
119 : ! Consider only the first -o flag
120 0 : i_arg = i_arg + 1
121 0 : CALL GET_COMMAND_ARGUMENT(NUMBER=i_arg, VALUE=arg_att, STATUS=ierr)
122 0 : CPASSERT(ierr == 0)
123 0 : IF (arg_att(1:1) == "-") THEN
124 : WRITE (output_unit, "(/,T2,A)") &
125 0 : "ERROR: The output file name "//TRIM(arg_att)//" starts with -"
126 0 : command_line_error = .TRUE.
127 : ELSE
128 0 : output_file_name = arg_att
129 : CALL open_file(file_name=output_file_name, &
130 : file_status="UNKNOWN", &
131 : file_action="WRITE", &
132 : file_position="APPEND", &
133 : skip_get_unit_number=.TRUE., &
134 0 : unit_number=output_unit)
135 : END IF
136 : ELSE
137 0 : i_arg = i_arg + 1
138 : WRITE (output_unit, "(/,T2,A)") &
139 0 : "ERROR: The command line flag -o has been specified multiple times"
140 0 : command_line_error = .TRUE.
141 : END IF
142 : END SELECT
143 : END DO
144 :
145 : ! Check if binary was invoked as cp2k_shell
146 10338 : IF (command(1:10) == "cp2k_shell") THEN
147 : shell_mode = .TRUE.
148 : run_it = .FALSE.
149 10338 : ELSE IF (COMMAND_ARGUMENT_COUNT() < 1) THEN
150 : WRITE (output_unit, "(/,T2,A)") &
151 0 : "ERROR: At least one command line argument must be specified"
152 0 : command_line_error = .TRUE.
153 : END IF
154 :
155 : ! Check if binary was invoked as sopt or popt alias
156 10338 : l = LEN_TRIM(command)
157 10338 : IF (l >= 5) THEN
158 10338 : IF (command(l - 4:l) == ".sopt" .OR. command(l - 4:l) == ".popt") THEN
159 0 : CALL omp_set_num_threads(1)
160 : END IF
161 : END IF
162 :
163 : #ifdef __ACCELERATE
164 : IF (omp_get_max_threads() > 1) THEN
165 : BLOCK
166 : CHARACTER(len=default_path_length) :: env_var
167 : INTEGER :: veclib_max_threads, ierr
168 : CALL get_environment_variable("VECLIB_MAXIMUM_THREADS", env_var, status=ierr)
169 : veclib_max_threads = 0
170 : IF (ierr == 0) &
171 : READ (env_var, *) veclib_max_threads
172 : IF (ierr == 1 .OR. (ierr == 0 .AND. veclib_max_threads > 1)) THEN
173 : CALL cp_warn(__LOCATION__, &
174 : "macOS' Accelerate framework has its own threading enabled which may interfere"// &
175 : " with the OpenMP threading. You can disable the Accelerate threading by setting"// &
176 : " the environment variable VECLIB_MAXIMUM_THREADS=1")
177 : END IF
178 : END BLOCK
179 : END IF
180 : #endif
181 :
182 10338 : i_arg = 0
183 20676 : arg_loop: DO WHILE (i_arg < COMMAND_ARGUMENT_COUNT())
184 10338 : i_arg = i_arg + 1
185 10338 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
186 10338 : CPASSERT(ierr == 0)
187 10338 : SELECT CASE (arg_att)
188 : CASE ("--check", "-c")
189 0 : check = .TRUE.
190 0 : run_it = .FALSE.
191 0 : echo_input = .FALSE.
192 : CASE ("--echo", "-e")
193 0 : check = .TRUE.
194 0 : run_it = .FALSE.
195 0 : echo_input = .TRUE.
196 : CASE ("-v", "--version")
197 : print_version = .TRUE.
198 0 : run_it = .FALSE.
199 : CASE ("--license")
200 0 : print_license = .TRUE.
201 0 : run_it = .FALSE.
202 : CASE ("--run", "-r")
203 0 : force_run = .TRUE.
204 : CASE ("--shell", "-s")
205 0 : shell_mode = .TRUE.
206 0 : run_it = .FALSE.
207 : CASE ("-help", "--help", "-h")
208 0 : usage = .TRUE.
209 0 : run_it = .FALSE.
210 : CASE ("-i")
211 0 : i_arg = i_arg + 1
212 0 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
213 0 : CPASSERT(ierr == 0)
214 : ! argument does not start with a - it is an filename
215 0 : IF (.NOT. arg_att(1:1) == "-") THEN
216 0 : input_file_name = arg_att
217 0 : has_input = .TRUE.
218 : ELSE
219 : WRITE (output_unit, "(/,T2,A)") &
220 0 : "ERROR: The input file name "//TRIM(arg_att)//" starts with -"
221 0 : command_line_error = .TRUE.
222 0 : EXIT arg_loop
223 : END IF
224 : CASE ("-E", "--set")
225 0 : i_arg = i_arg + 1
226 0 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
227 0 : CPASSERT(ierr == 0)
228 :
229 0 : var_set_sep = INDEX(arg_att, '=')
230 :
231 0 : IF (var_set_sep < 2) THEN
232 0 : WRITE (output_unit, "(/,T2,A)") "ERROR: Invalid initializer for preprocessor variable: "//TRIM(arg_att)
233 0 : command_line_error = .TRUE.
234 0 : EXIT arg_loop
235 : END IF
236 :
237 0 : DO inp_var_idx = 1, SIZE(initial_variables, 2)
238 : ! check whether the variable was already set, in this case, overwrite
239 0 : IF (TRIM(initial_variables(1, inp_var_idx)) == arg_att(:var_set_sep - 1)) &
240 0 : EXIT
241 : END DO
242 :
243 0 : IF (inp_var_idx > SIZE(initial_variables, 2)) THEN
244 : ! if the variable was never set before, extend the array
245 0 : ALLOCATE (initial_variables_tmp(2, SIZE(initial_variables, 2) + 1))
246 0 : initial_variables_tmp(:, 1:SIZE(initial_variables, 2)) = initial_variables
247 0 : CALL MOVE_ALLOC(initial_variables_tmp, initial_variables)
248 : END IF
249 :
250 0 : initial_variables(1, inp_var_idx) = arg_att(:var_set_sep - 1)
251 0 : initial_variables(2, inp_var_idx) = arg_att(var_set_sep + 1:)
252 : CASE ("-o")
253 : ! Skip -o flag which have been processed already
254 0 : i_arg = i_arg + 1
255 0 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
256 0 : CPASSERT(ierr == 0)
257 0 : IF (arg_att(1:1) == "-") EXIT arg_loop
258 : CASE ("--xml")
259 0 : xml = .TRUE.
260 0 : run_it = .FALSE.
261 : CASE DEFAULT
262 : ! if the last argument does not start with a - it is an input filename
263 : !MK in order to digest the additional flags of mpirun
264 : IF ((.NOT. has_input) .AND. &
265 10336 : (i_arg == COMMAND_ARGUMENT_COUNT()) .AND. &
266 10338 : (.NOT. arg_att(1:1) == "-")) THEN
267 10336 : input_file_name = arg_att
268 10336 : has_input = .TRUE.
269 0 : ELSE IF (has_input .AND. &
270 : (.NOT. arg_att(1:1) == "-")) THEN
271 : WRITE (output_unit, "(/,T2,A)") &
272 0 : "Error: Tried to specify two input files"
273 0 : command_line_error = .TRUE.
274 0 : EXIT arg_loop
275 : END IF
276 : END SELECT
277 : END DO arg_loop
278 :
279 : IF ((run_it .OR. force_run .OR. check .OR. echo_input) .AND. &
280 10338 : (.NOT. has_input) .AND. (.NOT. command_line_error)) THEN
281 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") &
282 0 : "ERROR: An input file name is required"
283 0 : command_line_error = .TRUE.
284 : END IF
285 :
286 10338 : CALL init_cp2k(init_mpi=.TRUE., ierr=ierr)
287 :
288 10338 : IF (ierr == 0) THEN
289 : ! some first info concerning how to run CP2K
290 :
291 10338 : IF (usage .OR. command_line_error) THEN
292 0 : IF (default_para_env%is_source()) THEN
293 0 : l = LEN_TRIM(command)
294 : WRITE (UNIT=output_unit, FMT="(/,(T2,A))") &
295 0 : TRIM(command)//" [-c|--check] [-e|--echo] [-h|--help]", &
296 0 : REPEAT(" ", l)//" [-i] <input_file>", &
297 0 : REPEAT(" ", l)//" [-mpi-mapping|--mpi-mapping] <method>", &
298 0 : REPEAT(" ", l)//" [-o] <output_file>", &
299 0 : REPEAT(" ", l)//" [-r|-run] [-s|--shell] [--xml]"
300 : WRITE (UNIT=output_unit, FMT="(/,T2,A,/,/,T2,A,/,/,T2,A,/,/,(T3,A))") &
301 0 : "starts the CP2K program, see <https://docker.axuan.wang/cp2k/>", &
302 0 : "The easiest way is "//TRIM(command)//" <input_file>", &
303 0 : "The following options can be used:", &
304 0 : "-i <input_file> : provides an input file name, if it is the last", &
305 0 : " argument, the -i flag is not needed", &
306 0 : "-o <output_file> : provides an output file name [default: screen]"
307 : WRITE (UNIT=output_unit, FMT="(/,T2,A,/,/,(T3,A))") &
308 0 : "These switches skip the simulation, unless [-r|-run] is specified:", &
309 0 : "--check, -c : performs a syntax check of the <input_file>", &
310 0 : "--echo, -e : echoes the <input_file>, and make all defaults explicit", &
311 0 : " The input is also checked, but only a failure is reported", &
312 0 : "--help, -h : writes this message", &
313 0 : "--license : prints the CP2K license", &
314 0 : "--mpi-mapping : applies a given MPI reordering to CP2K", &
315 0 : "--run, -r : forces a CP2K run regardless of other specified flags", &
316 0 : "--shell, -s : start interactive shell mode", &
317 0 : "--version, -v : prints the CP2K version and the revision number", &
318 0 : "--xml : dumps the whole CP2K input structure as a XML file", &
319 0 : " xml2htm generates a HTML manual from this XML file", &
320 0 : "--set, -E name=value : set the initial value of a preprocessor value", &
321 0 : ""
322 : END IF
323 : END IF
324 :
325 0 : IF (.NOT. command_line_error) THEN
326 :
327 : ! write the version string
328 10338 : IF (print_version) THEN
329 2 : IF (default_para_env%is_source()) THEN
330 1 : WRITE (output_unit, "(T2,A)") cp2k_version, &
331 1 : "Source code revision "//TRIM(compile_revision), &
332 2 : TRIM(cp2k_flags())
333 1 : compiler_options_string = compiler_options()
334 1 : WRITE (output_unit, "(T2,A,A)") "compiler: ", compiler_version()
335 1 : WRITE (output_unit, "(T2,A)") "compiler options:"
336 63 : DO i = 0, (LEN(compiler_options_string) - 1)/68
337 : WRITE (output_unit, "(T4,A)") &
338 63 : compiler_options_string(i*68 + 1:MIN(LEN(compiler_options_string), (i + 1)*68))
339 : END DO
340 1 : DEALLOCATE (compiler_options_string)
341 : END IF
342 : END IF
343 :
344 : ! write the license
345 10338 : IF (print_license) THEN
346 0 : IF (default_para_env%is_source()) THEN
347 0 : CALL print_cp2k_license(output_unit)
348 : END IF
349 : END IF
350 :
351 10338 : IF (xml) THEN
352 0 : IF (default_para_env%is_source()) THEN
353 0 : CALL write_xml_file()
354 : END IF
355 : END IF
356 :
357 10338 : CALL create_cp2k_root_section(input_declaration)
358 :
359 10338 : IF (check) THEN
360 : CALL check_input(input_declaration, input_file_name, output_file_name, &
361 0 : echo_input=echo_input, ierr=ierr, initial_variables=initial_variables)
362 0 : IF (default_para_env%is_source()) THEN
363 0 : IF (ierr == 0) THEN
364 0 : IF (.NOT. echo_input) THEN
365 0 : WRITE (output_unit, "(A)") "SUCCESS, the input could be parsed correctly."
366 0 : WRITE (output_unit, "(A)") " This does not guarantee that this input is meaningful"
367 0 : WRITE (output_unit, "(A)") " or will run successfully"
368 : END IF
369 : ELSE
370 0 : WRITE (output_unit, "(A)") "ERROR, the input could *NOT* be parsed correctly."
371 0 : WRITE (output_unit, "(A)") " Please, check and correct it"
372 : END IF
373 : END IF
374 : END IF
375 :
376 10338 : IF (shell_mode) THEN
377 0 : CALL launch_cp2k_shell(input_declaration)
378 : END IF
379 :
380 10338 : IF (run_it .OR. force_run) THEN
381 10336 : CALL run_input(input_declaration, input_file_name, output_file_name, initial_variables)
382 : END IF
383 :
384 10338 : CALL section_release(input_declaration)
385 : END IF
386 : ELSE
387 0 : WRITE (UNIT=output_unit, FMT="(/,A)") "initial setup (MPI ?) error"
388 : END IF
389 :
390 : ! and the final cleanup
391 10338 : CALL finalize_cp2k(finalize_mpi=.TRUE., ierr=ierr)
392 10338 : DEALLOCATE (initial_variables)
393 10338 : CPASSERT(ierr == 0)
394 :
395 10338 : END PROGRAM cp2k
|