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://www.cp2k.org/
37 : !> \note
38 : !> should be kept as lean as possible.
39 : !> see cp2k_run for more comments
40 : !> \author Joost VandeVondele
41 : ! **************************************************************************************************
42 1447 : PROGRAM cp2k
43 :
44 1447 : 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 f77_interface, ONLY: check_input,&
54 : default_para_env,&
55 : finalize_cp2k,&
56 : init_cp2k
57 : USE input_cp2k, ONLY: create_cp2k_root_section
58 : USE input_section_types, ONLY: section_release,&
59 : section_type
60 : USE iso_c_binding, ONLY: C_NULL_CHAR
61 : USE iso_fortran_env, ONLY: compiler_options,&
62 : compiler_version
63 : USE kinds, ONLY: default_path_length
64 : USE machine, ONLY: default_error_unit,&
65 : default_output_unit,&
66 : m_cpuid,&
67 : m_cpuid_name,&
68 : m_cpuid_static,&
69 : m_cpuid_vlen
70 : #include "../base/base_uses.f90"
71 :
72 : IMPLICIT NONE
73 :
74 : CHARACTER(LEN=default_path_length) :: input_file_name, output_file_name, &
75 : arg_att, command
76 : CHARACTER(LEN=default_path_length), &
77 1447 : DIMENSION(:, :), ALLOCATABLE :: initial_variables, initial_variables_tmp
78 1447 : CHARACTER(LEN=:), ALLOCATABLE :: compiler_options_string
79 : INTEGER :: cpuid, cpuid_static, output_unit, l, i, var_set_sep, inp_var_idx
80 : INTEGER :: ierr, i_arg
81 : LOGICAL :: check, usage, echo_input, command_line_error
82 : LOGICAL :: run_it, force_run, has_input, xml, print_version, print_license, shell_mode
83 : TYPE(section_type), POINTER :: input_declaration
84 :
85 1447 : NULLIFY (input_declaration)
86 :
87 : ! output goes to the screen by default
88 1447 : output_unit = default_output_unit
89 :
90 : ! set default behaviour for the command line switches
91 1447 : check = .FALSE.
92 1447 : usage = .FALSE.
93 1447 : echo_input = .FALSE.
94 1447 : has_input = .FALSE.
95 1447 : run_it = .TRUE.
96 1447 : shell_mode = .FALSE.
97 1447 : force_run = .FALSE.
98 1447 : print_version = .FALSE.
99 1447 : print_license = .FALSE.
100 1447 : command_line_error = .FALSE.
101 1447 : xml = .FALSE.
102 1447 : input_file_name = "Missing input file name" ! no default
103 1447 : output_file_name = "__STD_OUT__" ! by default we go to std_out
104 1447 : ALLOCATE (initial_variables(2, 1:0))
105 :
106 : ! Get command and strip path
107 1447 : CALL GET_COMMAND_ARGUMENT(NUMBER=0, VALUE=command, STATUS=ierr)
108 1447 : CPASSERT(ierr == 0)
109 1447 : l = LEN_TRIM(command)
110 14470 : DO i = l, 1, -1
111 14470 : IF (command(i:i) == "/" .OR. command(i:i) == "\") EXIT
112 : END DO
113 1447 : command = command(i + 1:l)
114 :
115 : ! Consider output redirection
116 1447 : i_arg = 0
117 2894 : DO WHILE (i_arg < COMMAND_ARGUMENT_COUNT())
118 1447 : i_arg = i_arg + 1
119 1447 : CALL GET_COMMAND_ARGUMENT(NUMBER=i_arg, VALUE=arg_att, STATUS=ierr)
120 1447 : CPASSERT(ierr == 0)
121 1447 : SELECT CASE (arg_att)
122 : CASE ("-o")
123 1447 : IF (output_file_name == "__STD_OUT__") THEN
124 : ! Consider only the first -o flag
125 0 : i_arg = i_arg + 1
126 0 : CALL GET_COMMAND_ARGUMENT(NUMBER=i_arg, VALUE=arg_att, STATUS=ierr)
127 0 : CPASSERT(ierr == 0)
128 0 : IF (arg_att(1:1) == "-") THEN
129 : WRITE (output_unit, "(/,T2,A)") &
130 0 : "ERROR: The output file name "//TRIM(arg_att)//" starts with -"
131 0 : command_line_error = .TRUE.
132 : ELSE
133 0 : output_file_name = arg_att
134 : ! Redirect the standard output (default_output_unit) to the output file
135 : OPEN (UNIT=output_unit, FILE=TRIM(output_file_name), STATUS="UNKNOWN", &
136 0 : FORM="FORMATTED", ACTION="WRITE", POSITION="APPEND", IOSTAT=ierr)
137 0 : IF (ierr /= 0) THEN
138 : ! The standard output might not be connected anymore
139 : WRITE (default_error_unit, "(/,T2,A)") &
140 0 : "ERROR: The output file "//TRIM(output_file_name)//" cannot be opened"
141 0 : command_line_error = .TRUE.
142 : END IF
143 : END IF
144 : ELSE
145 0 : i_arg = i_arg + 1
146 : WRITE (output_unit, "(/,T2,A)") &
147 0 : "ERROR: The command line flag -o has been specified multiple times"
148 0 : command_line_error = .TRUE.
149 : END IF
150 : END SELECT
151 : END DO
152 :
153 : ! Check if binary was invoked as cp2k_shell
154 1447 : IF (command(1:10) == "cp2k_shell") THEN
155 : shell_mode = .TRUE.
156 : run_it = .FALSE.
157 1447 : ELSE IF (COMMAND_ARGUMENT_COUNT() < 1) THEN
158 : WRITE (output_unit, "(/,T2,A)") &
159 0 : "ERROR: At least one command line argument must be specified"
160 0 : command_line_error = .TRUE.
161 : END IF
162 :
163 : ! Check if binary was invoked as sopt or popt alias
164 1447 : l = LEN_TRIM(command)
165 1447 : IF (l >= 5) THEN
166 1447 : IF (command(l - 4:l) == ".sopt" .OR. command(l - 4:l) == ".popt") THEN
167 0 : CALL omp_set_num_threads(1)
168 : END IF
169 : END IF
170 :
171 : #ifdef __ACCELERATE
172 : IF (omp_get_max_threads() > 1) THEN
173 : BLOCK
174 : CHARACTER(len=default_path_length) :: env_var
175 : INTEGER :: veclib_max_threads, ierr
176 : CALL get_environment_variable("VECLIB_MAXIMUM_THREADS", env_var, status=ierr)
177 : veclib_max_threads = 0
178 : IF (ierr == 0) THEN
179 : READ (env_var, *) veclib_max_threads
180 : END IF
181 : IF (ierr == 1 .OR. (ierr == 0 .AND. veclib_max_threads > 1)) THEN
182 : CALL cp_warn(__LOCATION__, &
183 : "macOS' Accelerate framework has its own threading enabled which may interfere"// &
184 : " with the OpenMP threading. You can disable the Accelerate threading by setting"// &
185 : " the environment variable VECLIB_MAXIMUM_THREADS=1")
186 : END IF
187 : END BLOCK
188 : END IF
189 : #endif
190 :
191 1447 : i_arg = 0
192 2894 : arg_loop: DO WHILE (i_arg < COMMAND_ARGUMENT_COUNT())
193 1447 : i_arg = i_arg + 1
194 1447 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
195 1447 : CPASSERT(ierr == 0)
196 1447 : SELECT CASE (arg_att)
197 : CASE ("--check", "-c")
198 0 : check = .TRUE.
199 0 : run_it = .FALSE.
200 0 : echo_input = .FALSE.
201 : CASE ("--echo", "-e")
202 0 : check = .TRUE.
203 0 : run_it = .FALSE.
204 0 : echo_input = .TRUE.
205 : CASE ("-v", "--version")
206 : print_version = .TRUE.
207 0 : run_it = .FALSE.
208 : CASE ("--license")
209 0 : print_license = .TRUE.
210 0 : run_it = .FALSE.
211 : CASE ("--run", "-r")
212 0 : force_run = .TRUE.
213 : CASE ("--shell", "-s")
214 1081 : shell_mode = .TRUE.
215 1081 : run_it = .FALSE.
216 : CASE ("-help", "--help", "-h")
217 0 : usage = .TRUE.
218 0 : run_it = .FALSE.
219 : CASE ("-i")
220 0 : i_arg = i_arg + 1
221 0 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
222 0 : CPASSERT(ierr == 0)
223 : ! argument does not start with a - it is an filename
224 0 : IF (.NOT. arg_att(1:1) == "-") THEN
225 0 : input_file_name = arg_att
226 0 : has_input = .TRUE.
227 : ELSE
228 : WRITE (output_unit, "(/,T2,A)") &
229 0 : "ERROR: The input file name "//TRIM(arg_att)//" starts with -"
230 0 : command_line_error = .TRUE.
231 0 : EXIT arg_loop
232 : END IF
233 : CASE ("-E", "--set")
234 0 : i_arg = i_arg + 1
235 0 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
236 0 : CPASSERT(ierr == 0)
237 :
238 0 : var_set_sep = INDEX(arg_att, '=')
239 :
240 0 : IF (var_set_sep < 2) THEN
241 0 : WRITE (output_unit, "(/,T2,A)") "ERROR: Invalid initializer for preprocessor variable: "//TRIM(arg_att)
242 0 : command_line_error = .TRUE.
243 0 : EXIT arg_loop
244 : END IF
245 :
246 0 : DO inp_var_idx = 1, SIZE(initial_variables, 2)
247 : ! check whether the variable was already set, in this case, overwrite
248 0 : IF (TRIM(initial_variables(1, inp_var_idx)) == arg_att(:var_set_sep - 1)) THEN
249 : EXIT
250 : END IF
251 : END DO
252 :
253 0 : IF (inp_var_idx > SIZE(initial_variables, 2)) THEN
254 : ! if the variable was never set before, extend the array
255 0 : ALLOCATE (initial_variables_tmp(2, SIZE(initial_variables, 2) + 1))
256 0 : initial_variables_tmp(:, 1:SIZE(initial_variables, 2)) = initial_variables
257 0 : CALL MOVE_ALLOC(initial_variables_tmp, initial_variables)
258 : END IF
259 :
260 0 : initial_variables(1, inp_var_idx) = arg_att(:var_set_sep - 1)
261 0 : initial_variables(2, inp_var_idx) = arg_att(var_set_sep + 1:)
262 : CASE ("-o")
263 : ! Skip -o flag which have been processed already
264 0 : i_arg = i_arg + 1
265 0 : CALL GET_COMMAND_ARGUMENT(i_arg, arg_att, status=ierr)
266 0 : CPASSERT(ierr == 0)
267 0 : IF (arg_att(1:1) == "-") EXIT arg_loop
268 : CASE ("--xml")
269 0 : xml = .TRUE.
270 0 : run_it = .FALSE.
271 : CASE DEFAULT
272 : ! if the last argument does not start with a - it is an input filename
273 : !MK in order to digest the additional flags of mpirun
274 : IF ((.NOT. has_input) .AND. &
275 364 : (i_arg == COMMAND_ARGUMENT_COUNT()) .AND. &
276 1447 : (.NOT. arg_att(1:1) == "-")) THEN
277 364 : input_file_name = arg_att
278 364 : has_input = .TRUE.
279 0 : ELSE IF (has_input .AND. &
280 : (.NOT. arg_att(1:1) == "-")) THEN
281 : WRITE (output_unit, "(/,T2,A)") &
282 0 : "Error: Tried to specify two input files"
283 0 : command_line_error = .TRUE.
284 0 : EXIT arg_loop
285 : END IF
286 : END SELECT
287 : END DO arg_loop
288 :
289 : IF ((run_it .OR. force_run .OR. check .OR. echo_input) .AND. &
290 1447 : (.NOT. has_input) .AND. (.NOT. command_line_error)) THEN
291 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") &
292 0 : "ERROR: An input file name is required"
293 0 : command_line_error = .TRUE.
294 : END IF
295 :
296 1447 : CALL init_cp2k(init_mpi=.TRUE., ierr=ierr)
297 :
298 1447 : IF (ierr == 0) THEN
299 : ! some first info concerning how to run CP2K
300 :
301 1447 : IF (usage .OR. command_line_error) THEN
302 0 : IF (default_para_env%is_source()) THEN
303 0 : l = LEN_TRIM(command)
304 : WRITE (UNIT=output_unit, FMT="(/,(T2,A))") &
305 0 : TRIM(command)//" [-c|--check] [-e|--echo] [-h|--help]", &
306 0 : REPEAT(" ", l)//" [-i] <input_file>", &
307 0 : REPEAT(" ", l)//" [-mpi-mapping|--mpi-mapping] <method>", &
308 0 : REPEAT(" ", l)//" [-o] <output_file>", &
309 0 : REPEAT(" ", l)//" [-r|-run] [-s|--shell] [--xml]"
310 : WRITE (UNIT=output_unit, FMT="(/,T2,A,/,/,T2,A,/,/,T2,A,/,/,(T3,A))") &
311 0 : "starts the CP2K program, see <https://www.cp2k.org/>", &
312 0 : "The easiest way is "//TRIM(command)//" <input_file>", &
313 0 : "The following options can be used:", &
314 0 : "-i <input_file> : provides an input file name, if it is the last", &
315 0 : " argument, the -i flag is not needed", &
316 0 : "-o <output_file> : provides an output file name [default: screen]"
317 : WRITE (UNIT=output_unit, FMT="(/,T2,A,/,/,(T3,A))") &
318 0 : "These switches skip the simulation, unless [-r|-run] is specified:", &
319 0 : "--check, -c : performs a syntax check of the <input_file>", &
320 0 : "--echo, -e : echoes the <input_file>, and make all defaults explicit", &
321 0 : " The input is also checked, but only a failure is reported", &
322 0 : "--help, -h : writes this message", &
323 0 : "--license : prints the CP2K license", &
324 0 : "--mpi-mapping : applies a given MPI reordering to CP2K", &
325 0 : "--run, -r : forces a CP2K run regardless of other specified flags", &
326 0 : "--shell, -s : start interactive shell mode", &
327 0 : "--version, -v : prints the CP2K version and the revision number", &
328 0 : "--xml : dumps the whole CP2K input structure as a XML file", &
329 0 : " xml2htm generates a HTML manual from this XML file", &
330 0 : "--set, -E name=value : set the initial value of a preprocessor value", &
331 0 : ""
332 : END IF
333 : END IF
334 :
335 0 : IF (.NOT. command_line_error) THEN
336 :
337 : ! write the version string
338 1447 : IF (print_version) THEN
339 2 : IF (default_para_env%is_source()) THEN
340 1 : WRITE (output_unit, "(T2,A)") cp2k_version, &
341 1 : "Source code revision "//TRIM(compile_revision), &
342 2 : TRIM(cp2k_flags())
343 : ! The trailing NUL character bounds the in-place prefix replacement of
344 : ! package managers like conda to this string, which would otherwise
345 : ! shift and corrupt the subsequent string literals in the binary
346 1 : compiler_options_string = compiler_options()//C_NULL_CHAR
347 1 : l = INDEX(compiler_options_string, C_NULL_CHAR) - 1
348 1 : WRITE (output_unit, "(T2,A,A)") "compiler: ", compiler_version()
349 1 : cpuid = m_cpuid()
350 1 : cpuid_static = m_cpuid_static()
351 1 : IF ((cpuid > 0) .OR. (cpuid_static > 0)) THEN
352 : WRITE (output_unit, "(T2,A,1X,I6,1X,A)") &
353 1 : "compiler target: cpuid", cpuid_static, "("//TRIM(m_cpuid_name(cpuid_static))//")"
354 1 : IF (cpuid /= cpuid_static) THEN
355 : WRITE (output_unit, "(T2,A,1X,I6,1X,A)") &
356 1 : "current: cpuid", cpuid, "("//TRIM(m_cpuid_name(cpuid))//")"
357 : END IF
358 : END IF
359 1 : IF (m_cpuid_vlen(cpuid_static) < m_cpuid_vlen(cpuid)) THEN
360 : WRITE (output_unit, "(T2,A)") &
361 : "WARNING: The compiler target used to build this binary does not "// &
362 : "enable all instruction-set extensions available on this CPU. "// &
363 : "Consider reconfiguring and rebuilding CP2K for this target system "// &
364 1 : "to enable them."
365 : END IF
366 1 : WRITE (output_unit, "(T2,A)") "compiler options:"
367 45 : DO i = 0, (l - 1)/68
368 : WRITE (output_unit, "(T4,A)") &
369 45 : compiler_options_string(i*68 + 1:MIN(l, (i + 1)*68))
370 : END DO
371 1 : DEALLOCATE (compiler_options_string)
372 : END IF
373 : END IF
374 :
375 : ! write the license
376 1447 : IF (print_license) THEN
377 0 : IF (default_para_env%is_source()) THEN
378 0 : CALL print_cp2k_license(output_unit)
379 : END IF
380 : END IF
381 :
382 1447 : IF (xml) THEN
383 0 : IF (default_para_env%is_source()) THEN
384 0 : CALL write_xml_file()
385 : END IF
386 : END IF
387 :
388 1447 : CALL create_cp2k_root_section(input_declaration)
389 :
390 1447 : IF (check) THEN
391 : CALL check_input(input_declaration, input_file_name, output_file_name, &
392 0 : echo_input=echo_input, ierr=ierr, initial_variables=initial_variables)
393 0 : IF (default_para_env%is_source()) THEN
394 0 : IF (ierr == 0) THEN
395 0 : IF (.NOT. echo_input) THEN
396 0 : WRITE (output_unit, "(A)") "SUCCESS, the input could be parsed correctly."
397 0 : WRITE (output_unit, "(A)") " This does not guarantee that this input is meaningful"
398 0 : WRITE (output_unit, "(A)") " or will run successfully"
399 : END IF
400 : ELSE
401 0 : WRITE (output_unit, "(A)") "ERROR, the input could *NOT* be parsed correctly."
402 0 : WRITE (output_unit, "(A)") " Please, check and correct it"
403 : END IF
404 : END IF
405 : END IF
406 :
407 1447 : IF (shell_mode) THEN
408 1081 : CALL launch_cp2k_shell(input_declaration)
409 : END IF
410 :
411 1446 : IF (run_it .OR. force_run) THEN
412 364 : CALL run_input(input_declaration, input_file_name, output_file_name, initial_variables)
413 : END IF
414 :
415 1446 : CALL section_release(input_declaration)
416 : END IF
417 : ELSE
418 0 : WRITE (UNIT=output_unit, FMT="(/,A)") "initial setup (MPI ?) error"
419 : END IF
420 :
421 : ! and the final cleanup
422 1446 : CALL finalize_cp2k(finalize_mpi=.TRUE., ierr=ierr)
423 1446 : DEALLOCATE (initial_variables)
424 1446 : CPASSERT(ierr == 0)
425 :
426 1446 : END PROGRAM cp2k
|