Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief represents keywords in an input
10 : !> \par History
11 : !> 06.2004 created, based on Joost cp_keywords proposal [fawzi]
12 : !> \author fawzi
13 : ! **************************************************************************************************
14 : MODULE input_keyword_types
15 : USE cp_units, ONLY: cp_unit_create,&
16 : cp_unit_desc,&
17 : cp_unit_release,&
18 : cp_unit_type
19 : USE input_enumeration_types, ONLY: enum_create,&
20 : enum_release,&
21 : enum_retain,&
22 : enumeration_type
23 : USE input_val_types, ONLY: &
24 : char_t, enum_t, integer_t, lchar_t, logical_t, no_t, real_t, val_create, val_release, &
25 : val_retain, val_type, val_write, val_write_internal
26 : USE kinds, ONLY: default_string_length,&
27 : dp
28 : USE print_messages, ONLY: print_message
29 : USE reference_manager, ONLY: get_citation_key
30 : USE string_utilities, ONLY: a2s,&
31 : compress,&
32 : substitute_special_xml_tokens,&
33 : typo_match,&
34 : uppercase
35 : #include "../base/base_uses.f90"
36 :
37 : IMPLICIT NONE
38 : PRIVATE
39 :
40 : LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
41 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'input_keyword_types'
42 :
43 : INTEGER, PARAMETER, PUBLIC :: usage_string_length = default_string_length*2
44 :
45 : PUBLIC :: keyword_p_type, keyword_type, keyword_create, keyword_retain, &
46 : keyword_release, keyword_get, keyword_describe, &
47 : write_keyword_xml, keyword_typo_match
48 :
49 : ! **************************************************************************************************
50 : !> \brief represent a pointer to a keyword (to make arrays of pointers)
51 : !> \param keyword the pointer to the keyword
52 : !> \author fawzi
53 : ! **************************************************************************************************
54 : TYPE keyword_p_type
55 : TYPE(keyword_type), POINTER :: keyword => NULL()
56 : END TYPE keyword_p_type
57 :
58 : ! **************************************************************************************************
59 : !> \brief represent a keyword in the input
60 : !> \param names the names of the current keyword (at least one should be
61 : !> present) for example "MAXSCF"
62 : !> \param location is where in the source code (file and line) the keyword is created
63 : !> \param usage how to use it "MAXSCF 10"
64 : !> \param description what does it do: "MAXSCF : determines the maximum
65 : !> number of steps in an SCF run"
66 : !> \param deprecation_notice show this warning that the keyword is deprecated
67 : !> \param citations references to literature associated with this keyword
68 : !> \param type_of_var the type of keyword (controls how it is parsed)
69 : !> it can be one of: no_parse_t,logical_t, integer_t, real_t,
70 : !> char_t
71 : !> \param n_var number of values that should be parsed (-1=unknown)
72 : !> \param repeats if the keyword can be present more than once in the
73 : !> section
74 : !> \param removed to trigger a CPABORT when encountered while parsing the input
75 : !> \param enum enumeration that defines the mapping between integers and
76 : !> strings
77 : !> \param unit the default unit this keyword is read in (to automatically
78 : !> convert to the internal cp2k units during parsing)
79 : !> \param default_value the default value for the keyword
80 : !> \param lone_keyword_value value to be used in presence of the keyword
81 : !> without any parameter
82 : !> \note
83 : !> I have expressely avoided a format string for the type of keywords:
84 : !> they should easily map to basic types of fortran, if you need more
85 : !> information use a subsection. [fawzi]
86 : !> \author Joost & fawzi
87 : ! **************************************************************************************************
88 : TYPE keyword_type
89 : INTEGER :: ref_count = 0
90 : CHARACTER(LEN=default_string_length), DIMENSION(:), POINTER :: names => NULL()
91 : CHARACTER(LEN=usage_string_length) :: location = ""
92 : CHARACTER(LEN=usage_string_length) :: usage = ""
93 : CHARACTER, DIMENSION(:), POINTER :: description => null()
94 : CHARACTER(LEN=:), ALLOCATABLE :: deprecation_notice
95 : INTEGER, POINTER, DIMENSION(:) :: citations => NULL()
96 : INTEGER :: type_of_var = 0, n_var = 0
97 : LOGICAL :: repeats = .FALSE., removed = .FALSE.
98 : TYPE(enumeration_type), POINTER :: enum => NULL()
99 : TYPE(cp_unit_type), POINTER :: unit => NULL()
100 : TYPE(val_type), POINTER :: default_value => NULL()
101 : TYPE(val_type), POINTER :: lone_keyword_value => NULL()
102 : END TYPE keyword_type
103 :
104 : CONTAINS
105 :
106 : ! **************************************************************************************************
107 : !> \brief creates a keyword object
108 : !> \param keyword the keyword object to be created
109 : !> \param location from where in the source code keyword_create() is called
110 : !> \param name the name of the keyword
111 : !> \param description ...
112 : !> \param usage ...
113 : !> \param type_of_var ...
114 : !> \param n_var ...
115 : !> \param repeats ...
116 : !> \param variants ...
117 : !> \param default_val ...
118 : !> \param default_l_val ...
119 : !> \param default_r_val ...
120 : !> \param default_lc_val ...
121 : !> \param default_c_val ...
122 : !> \param default_i_val ...
123 : !> \param default_l_vals ...
124 : !> \param default_r_vals ...
125 : !> \param default_c_vals ...
126 : !> \param default_i_vals ...
127 : !> \param lone_keyword_val ...
128 : !> \param lone_keyword_l_val ...
129 : !> \param lone_keyword_r_val ...
130 : !> \param lone_keyword_c_val ...
131 : !> \param lone_keyword_i_val ...
132 : !> \param lone_keyword_l_vals ...
133 : !> \param lone_keyword_r_vals ...
134 : !> \param lone_keyword_c_vals ...
135 : !> \param lone_keyword_i_vals ...
136 : !> \param enum_c_vals ...
137 : !> \param enum_i_vals ...
138 : !> \param enum ...
139 : !> \param enum_strict ...
140 : !> \param enum_desc ...
141 : !> \param unit_str ...
142 : !> \param citations ...
143 : !> \param deprecation_notice ...
144 : !> \param removed ...
145 : !> \author fawzi
146 : ! **************************************************************************************************
147 597096242 : SUBROUTINE keyword_create(keyword, location, name, description, usage, type_of_var, &
148 9925027 : n_var, repeats, variants, default_val, &
149 : default_l_val, default_r_val, default_lc_val, default_c_val, default_i_val, &
150 597096242 : default_l_vals, default_r_vals, default_c_vals, default_i_vals, &
151 : lone_keyword_val, lone_keyword_l_val, lone_keyword_r_val, lone_keyword_c_val, &
152 1194192484 : lone_keyword_i_val, lone_keyword_l_vals, lone_keyword_r_vals, &
153 1791288726 : lone_keyword_c_vals, lone_keyword_i_vals, enum_c_vals, enum_i_vals, &
154 1194192484 : enum, enum_strict, enum_desc, unit_str, citations, deprecation_notice, removed)
155 : TYPE(keyword_type), POINTER :: keyword
156 : CHARACTER(len=*), INTENT(in) :: location, name, description
157 : CHARACTER(len=*), INTENT(in), OPTIONAL :: usage
158 : INTEGER, INTENT(in), OPTIONAL :: type_of_var, n_var
159 : LOGICAL, INTENT(in), OPTIONAL :: repeats
160 : CHARACTER(len=*), DIMENSION(:), INTENT(in), &
161 : OPTIONAL :: variants
162 : TYPE(val_type), OPTIONAL, POINTER :: default_val
163 : LOGICAL, INTENT(in), OPTIONAL :: default_l_val
164 : REAL(KIND=DP), INTENT(in), OPTIONAL :: default_r_val
165 : CHARACTER(len=*), INTENT(in), OPTIONAL :: default_lc_val, default_c_val
166 : INTEGER, INTENT(in), OPTIONAL :: default_i_val
167 : LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL :: default_l_vals
168 : REAL(KIND=DP), DIMENSION(:), INTENT(in), OPTIONAL :: default_r_vals
169 : CHARACTER(len=*), DIMENSION(:), INTENT(in), &
170 : OPTIONAL :: default_c_vals
171 : INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: default_i_vals
172 : TYPE(val_type), OPTIONAL, POINTER :: lone_keyword_val
173 : LOGICAL, INTENT(in), OPTIONAL :: lone_keyword_l_val
174 : REAL(KIND=DP), INTENT(in), OPTIONAL :: lone_keyword_r_val
175 : CHARACTER(len=*), INTENT(in), OPTIONAL :: lone_keyword_c_val
176 : INTEGER, INTENT(in), OPTIONAL :: lone_keyword_i_val
177 : LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL :: lone_keyword_l_vals
178 : REAL(KIND=DP), DIMENSION(:), INTENT(in), OPTIONAL :: lone_keyword_r_vals
179 : CHARACTER(len=*), DIMENSION(:), INTENT(in), &
180 : OPTIONAL :: lone_keyword_c_vals
181 : INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: lone_keyword_i_vals
182 : CHARACTER(len=*), DIMENSION(:), INTENT(in), &
183 : OPTIONAL :: enum_c_vals
184 : INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: enum_i_vals
185 : TYPE(enumeration_type), OPTIONAL, POINTER :: enum
186 : LOGICAL, INTENT(in), OPTIONAL :: enum_strict
187 : CHARACTER(len=*), DIMENSION(:), INTENT(in), &
188 : OPTIONAL :: enum_desc
189 : CHARACTER(len=*), INTENT(in), OPTIONAL :: unit_str
190 : INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: citations
191 : CHARACTER(len=*), INTENT(in), OPTIONAL :: deprecation_notice
192 : LOGICAL, INTENT(in), OPTIONAL :: removed
193 :
194 : CHARACTER(LEN=default_string_length) :: tmp_string
195 : INTEGER :: i, n
196 : LOGICAL :: check
197 :
198 597096242 : CPASSERT(.NOT. ASSOCIATED(keyword))
199 597096242 : ALLOCATE (keyword)
200 597096242 : keyword%ref_count = 1
201 : NULLIFY (keyword%unit)
202 597096242 : keyword%location = location
203 597096242 : keyword%removed = .FALSE.
204 :
205 597096242 : CPASSERT(LEN_TRIM(name) > 0)
206 :
207 597096242 : IF (PRESENT(variants)) THEN
208 29775081 : ALLOCATE (keyword%names(SIZE(variants) + 1))
209 9925027 : keyword%names(1) = name
210 22316522 : DO i = 1, SIZE(variants)
211 12391495 : CPASSERT(LEN_TRIM(variants(i)) > 0)
212 22316522 : keyword%names(i + 1) = variants(i)
213 : END DO
214 : ELSE
215 587171215 : ALLOCATE (keyword%names(1))
216 587171215 : keyword%names(1) = name
217 : END IF
218 1206583979 : DO i = 1, SIZE(keyword%names)
219 1206583979 : CALL uppercase(keyword%names(i))
220 : END DO
221 :
222 597096242 : IF (PRESENT(usage)) THEN
223 218531110 : CPASSERT(LEN_TRIM(usage) <= LEN(keyword%usage))
224 218531110 : keyword%usage = usage
225 : ! Check that the usage string starts with one of the keyword names.
226 218531110 : IF (keyword%names(1) /= "_SECTION_PARAMETERS_" .AND. keyword%names(1) /= "_DEFAULT_KEYWORD_") THEN
227 208875151 : tmp_string = usage
228 208875151 : CALL uppercase(tmp_string)
229 208875151 : check = .FALSE.
230 427981400 : DO i = 1, SIZE(keyword%names)
231 428859134 : check = check .OR. (INDEX(tmp_string, TRIM(keyword%names(i))) == 1)
232 : END DO
233 208875151 : IF (.NOT. check) THEN
234 0 : CPABORT("Usage string must start with one of the keyword name.")
235 : END IF
236 : END IF
237 : ELSE
238 378565132 : keyword%usage = ""
239 : END IF
240 :
241 597096242 : n = LEN_TRIM(description)
242 1790949322 : ALLOCATE (keyword%description(n))
243 29808592417 : DO i = 1, n
244 29808592417 : keyword%description(i) = description(i:i)
245 : END DO
246 :
247 597096242 : IF (PRESENT(citations)) THEN
248 3101895 : ALLOCATE (keyword%citations(SIZE(citations, 1)))
249 2983730 : keyword%citations = citations
250 : ELSE
251 596062277 : NULLIFY (keyword%citations)
252 : END IF
253 :
254 597096242 : keyword%repeats = .FALSE.
255 597096242 : IF (PRESENT(repeats)) keyword%repeats = repeats
256 :
257 597096242 : NULLIFY (keyword%enum)
258 597096242 : IF (PRESENT(enum)) THEN
259 0 : keyword%enum => enum
260 0 : IF (ASSOCIATED(enum)) CALL enum_retain(enum)
261 : END IF
262 597096242 : IF (PRESENT(enum_i_vals)) THEN
263 22730034 : CPASSERT(PRESENT(enum_c_vals))
264 22730034 : CPASSERT(.NOT. ASSOCIATED(keyword%enum))
265 : CALL enum_create(keyword%enum, c_vals=enum_c_vals, i_vals=enum_i_vals, &
266 31166581 : desc=enum_desc, strict=enum_strict)
267 : ELSE
268 574366208 : CPASSERT(.NOT. PRESENT(enum_c_vals))
269 : END IF
270 :
271 597096242 : NULLIFY (keyword%default_value, keyword%lone_keyword_value)
272 597096242 : IF (PRESENT(default_val)) THEN
273 : IF (PRESENT(default_l_val) .OR. PRESENT(default_l_vals) .OR. &
274 : PRESENT(default_i_val) .OR. PRESENT(default_i_vals) .OR. &
275 : PRESENT(default_r_val) .OR. PRESENT(default_r_vals) .OR. &
276 0 : PRESENT(default_c_val) .OR. PRESENT(default_c_vals)) &
277 0 : CPABORT("you should pass either default_val or a default value, not both")
278 0 : keyword%default_value => default_val
279 0 : IF (ASSOCIATED(default_val%enum)) THEN
280 0 : IF (ASSOCIATED(keyword%enum)) THEN
281 0 : CPASSERT(ASSOCIATED(keyword%enum, default_val%enum))
282 : ELSE
283 0 : keyword%enum => default_val%enum
284 0 : CALL enum_retain(keyword%enum)
285 : END IF
286 : ELSE
287 0 : CPASSERT(.NOT. ASSOCIATED(keyword%enum))
288 : END IF
289 0 : CALL val_retain(default_val)
290 : END IF
291 597096242 : IF (.NOT. ASSOCIATED(keyword%default_value)) THEN
292 : CALL val_create(keyword%default_value, l_val=default_l_val, &
293 : l_vals=default_l_vals, i_val=default_i_val, i_vals=default_i_vals, &
294 : r_val=default_r_val, r_vals=default_r_vals, c_val=default_c_val, &
295 4167107058 : c_vals=default_c_vals, lc_val=default_lc_val, enum=keyword%enum)
296 : END IF
297 :
298 597096242 : keyword%type_of_var = keyword%default_value%type_of_var
299 597096242 : IF (keyword%default_value%type_of_var == no_t) THEN
300 15476884 : CALL val_release(keyword%default_value)
301 : END IF
302 :
303 597096242 : IF (keyword%type_of_var == no_t) THEN
304 15476884 : IF (PRESENT(type_of_var)) THEN
305 15476884 : keyword%type_of_var = type_of_var
306 : ELSE
307 : CALL cp_abort(__LOCATION__, &
308 : "keyword "//TRIM(keyword%names(1))// &
309 0 : " assumed undefined type by default")
310 : END IF
311 581619358 : ELSE IF (PRESENT(type_of_var)) THEN
312 12460096 : IF (keyword%type_of_var /= type_of_var) &
313 : CALL cp_abort(__LOCATION__, &
314 : "keyword "//TRIM(keyword%names(1))// &
315 0 : " has a type different from the type of the default_value")
316 12460096 : keyword%type_of_var = type_of_var
317 : END IF
318 :
319 597096242 : IF (keyword%type_of_var == no_t) THEN
320 0 : CALL val_create(keyword%default_value)
321 : END IF
322 :
323 597096242 : IF (PRESENT(lone_keyword_val)) THEN
324 : IF (PRESENT(lone_keyword_l_val) .OR. PRESENT(lone_keyword_l_vals) .OR. &
325 : PRESENT(lone_keyword_i_val) .OR. PRESENT(lone_keyword_i_vals) .OR. &
326 : PRESENT(lone_keyword_r_val) .OR. PRESENT(lone_keyword_r_vals) .OR. &
327 0 : PRESENT(lone_keyword_c_val) .OR. PRESENT(lone_keyword_c_vals)) &
328 : CALL cp_abort(__LOCATION__, &
329 0 : "you should pass either lone_keyword_val or a lone_keyword value, not both")
330 0 : keyword%lone_keyword_value => lone_keyword_val
331 0 : CALL val_retain(lone_keyword_val)
332 0 : IF (ASSOCIATED(lone_keyword_val%enum)) THEN
333 0 : IF (ASSOCIATED(keyword%enum)) THEN
334 0 : IF (.NOT. ASSOCIATED(keyword%enum, lone_keyword_val%enum)) &
335 0 : CPABORT("keyword%enum/=lone_keyword_val%enum")
336 : ELSE
337 0 : IF (ASSOCIATED(keyword%lone_keyword_value)) THEN
338 0 : CPABORT(".NOT. ASSOCIATED(keyword%lone_keyword_value)")
339 : END IF
340 0 : keyword%enum => lone_keyword_val%enum
341 0 : CALL enum_retain(keyword%enum)
342 : END IF
343 : ELSE
344 0 : CPASSERT(.NOT. ASSOCIATED(keyword%enum))
345 : END IF
346 : END IF
347 597096242 : IF (.NOT. ASSOCIATED(keyword%lone_keyword_value)) THEN
348 : CALL val_create(keyword%lone_keyword_value, l_val=lone_keyword_l_val, &
349 : l_vals=lone_keyword_l_vals, i_val=lone_keyword_i_val, i_vals=lone_keyword_i_vals, &
350 : r_val=lone_keyword_r_val, r_vals=lone_keyword_r_vals, c_val=lone_keyword_c_val, &
351 3582457550 : c_vals=lone_keyword_c_vals, enum=keyword%enum)
352 : END IF
353 597096242 : IF (ASSOCIATED(keyword%lone_keyword_value)) THEN
354 597096242 : IF (keyword%lone_keyword_value%type_of_var == no_t) THEN
355 515944721 : CALL val_release(keyword%lone_keyword_value)
356 : ELSE
357 81151521 : IF (keyword%lone_keyword_value%type_of_var /= keyword%type_of_var) &
358 0 : CPABORT("lone_keyword_value type incompatible with keyword type")
359 : ! lc_val cannot have lone_keyword_value!
360 81151521 : IF (keyword%type_of_var == enum_t) THEN
361 6545397 : IF (keyword%enum%strict) THEN
362 6545397 : check = .FALSE.
363 52265360 : DO i = 1, SIZE(keyword%enum%i_vals)
364 79288633 : check = check .OR. (keyword%default_value%i_val(1) == keyword%enum%i_vals(i))
365 : END DO
366 6545397 : IF (.NOT. check) &
367 0 : CPABORT("default value not in enumeration : "//keyword%names(1))
368 : END IF
369 : END IF
370 : END IF
371 : END IF
372 :
373 597096242 : keyword%n_var = 1
374 597096242 : IF (ASSOCIATED(keyword%default_value)) THEN
375 657528665 : SELECT CASE (keyword%default_value%type_of_var)
376 : CASE (logical_t)
377 75909307 : keyword%n_var = SIZE(keyword%default_value%l_val)
378 : CASE (integer_t)
379 142654172 : keyword%n_var = SIZE(keyword%default_value%i_val)
380 : CASE (enum_t)
381 22645085 : IF (keyword%enum%strict) THEN
382 22645085 : check = .FALSE.
383 126917178 : DO i = 1, SIZE(keyword%enum%i_vals)
384 162397660 : check = check .OR. (keyword%default_value%i_val(1) == keyword%enum%i_vals(i))
385 : END DO
386 22645085 : IF (.NOT. check) &
387 0 : CPABORT("default value not in enumeration : "//keyword%names(1))
388 : END IF
389 22645085 : keyword%n_var = SIZE(keyword%default_value%i_val)
390 : CASE (real_t)
391 331058579 : keyword%n_var = SIZE(keyword%default_value%r_val)
392 : CASE (char_t)
393 2082404 : keyword%n_var = SIZE(keyword%default_value%c_val)
394 : CASE (lchar_t)
395 7269811 : keyword%n_var = 1
396 : CASE (no_t)
397 0 : keyword%n_var = 0
398 : CASE default
399 581619358 : CPABORT("")
400 : END SELECT
401 : END IF
402 597096242 : IF (PRESENT(n_var)) keyword%n_var = n_var
403 597096242 : IF (keyword%type_of_var == lchar_t .AND. keyword%n_var /= 1) &
404 0 : CPABORT("arrays of lchar_t not supported : "//keyword%names(1))
405 :
406 597096242 : IF (PRESENT(unit_str)) THEN
407 305884400 : ALLOCATE (keyword%unit)
408 12235376 : CALL cp_unit_create(keyword%unit, unit_str)
409 : END IF
410 :
411 597096242 : IF (PRESENT(deprecation_notice)) THEN
412 104820 : keyword%deprecation_notice = TRIM(deprecation_notice)
413 : END IF
414 :
415 597096242 : IF (PRESENT(removed)) THEN
416 36888 : keyword%removed = removed
417 : END IF
418 597096242 : END SUBROUTINE keyword_create
419 :
420 : ! **************************************************************************************************
421 : !> \brief retains the given keyword (see doc/ReferenceCounting.html)
422 : !> \param keyword the keyword to retain
423 : !> \author fawzi
424 : ! **************************************************************************************************
425 597096242 : SUBROUTINE keyword_retain(keyword)
426 : TYPE(keyword_type), POINTER :: keyword
427 :
428 597096242 : CPASSERT(ASSOCIATED(keyword))
429 597096242 : CPASSERT(keyword%ref_count > 0)
430 597096242 : keyword%ref_count = keyword%ref_count + 1
431 597096242 : END SUBROUTINE keyword_retain
432 :
433 : ! **************************************************************************************************
434 : !> \brief releases the given keyword (see doc/ReferenceCounting.html)
435 : !> \param keyword the keyword to release
436 : !> \author fawzi
437 : ! **************************************************************************************************
438 1542015039 : SUBROUTINE keyword_release(keyword)
439 : TYPE(keyword_type), POINTER :: keyword
440 :
441 1542015039 : IF (ASSOCIATED(keyword)) THEN
442 1194192484 : CPASSERT(keyword%ref_count > 0)
443 1194192484 : keyword%ref_count = keyword%ref_count - 1
444 1194192484 : IF (keyword%ref_count == 0) THEN
445 597096242 : DEALLOCATE (keyword%names)
446 597096242 : DEALLOCATE (keyword%description)
447 597096242 : CALL val_release(keyword%default_value)
448 597096242 : CALL val_release(keyword%lone_keyword_value)
449 597096242 : CALL enum_release(keyword%enum)
450 597096242 : IF (ASSOCIATED(keyword%unit)) THEN
451 12235376 : CALL cp_unit_release(keyword%unit)
452 12235376 : DEALLOCATE (keyword%unit)
453 : END IF
454 597096242 : IF (ASSOCIATED(keyword%citations)) THEN
455 1033965 : DEALLOCATE (keyword%citations)
456 : END IF
457 597096242 : DEALLOCATE (keyword)
458 : END IF
459 : END IF
460 1542015039 : NULLIFY (keyword)
461 1542015039 : END SUBROUTINE keyword_release
462 :
463 : ! **************************************************************************************************
464 : !> \brief ...
465 : !> \param keyword ...
466 : !> \param names ...
467 : !> \param usage ...
468 : !> \param description ...
469 : !> \param type_of_var ...
470 : !> \param n_var ...
471 : !> \param default_value ...
472 : !> \param lone_keyword_value ...
473 : !> \param repeats ...
474 : !> \param enum ...
475 : !> \param citations ...
476 : !> \author fawzi
477 : ! **************************************************************************************************
478 50280 : SUBROUTINE keyword_get(keyword, names, usage, description, type_of_var, n_var, &
479 : default_value, lone_keyword_value, repeats, enum, citations)
480 : TYPE(keyword_type), POINTER :: keyword
481 : CHARACTER(len=default_string_length), &
482 : DIMENSION(:), OPTIONAL, POINTER :: names
483 : CHARACTER(len=*), INTENT(out), OPTIONAL :: usage, description
484 : INTEGER, INTENT(out), OPTIONAL :: type_of_var, n_var
485 : TYPE(val_type), OPTIONAL, POINTER :: default_value, lone_keyword_value
486 : LOGICAL, INTENT(out), OPTIONAL :: repeats
487 : TYPE(enumeration_type), OPTIONAL, POINTER :: enum
488 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: citations
489 :
490 0 : CPASSERT(ASSOCIATED(keyword))
491 50280 : CPASSERT(keyword%ref_count > 0)
492 50280 : IF (PRESENT(names)) names => keyword%names
493 50280 : IF (PRESENT(usage)) usage = keyword%usage
494 50280 : IF (PRESENT(description)) description = a2s(keyword%description)
495 50280 : IF (PRESENT(type_of_var)) type_of_var = keyword%type_of_var
496 50280 : IF (PRESENT(n_var)) n_var = keyword%n_var
497 50280 : IF (PRESENT(repeats)) repeats = keyword%repeats
498 50280 : IF (PRESENT(default_value)) default_value => keyword%default_value
499 50280 : IF (PRESENT(lone_keyword_value)) lone_keyword_value => keyword%lone_keyword_value
500 50280 : IF (PRESENT(enum)) enum => keyword%enum
501 50280 : IF (PRESENT(citations)) citations => keyword%citations
502 50280 : END SUBROUTINE keyword_get
503 :
504 : ! **************************************************************************************************
505 : !> \brief writes out a description of the keyword
506 : !> \param keyword the keyword to describe
507 : !> \param unit_nr the unit to write to
508 : !> \param level the description level (0 no description, 1 name
509 : !> 2: +usage, 3: +variants+description+default_value+repeats
510 : !> 4: +type_of_var)
511 : !> \author fawzi
512 : ! **************************************************************************************************
513 19 : SUBROUTINE keyword_describe(keyword, unit_nr, level)
514 : TYPE(keyword_type), POINTER :: keyword
515 : INTEGER, INTENT(in) :: unit_nr, level
516 :
517 : CHARACTER(len=default_string_length) :: c_string
518 : INTEGER :: i, l
519 :
520 19 : CPASSERT(ASSOCIATED(keyword))
521 19 : CPASSERT(keyword%ref_count > 0)
522 19 : IF (level > 0 .AND. (unit_nr > 0)) THEN
523 19 : WRITE (unit_nr, "(a,a,a)") " ---", &
524 38 : TRIM(keyword%names(1)), "---"
525 19 : IF (level > 1) THEN
526 19 : WRITE (unit_nr, "(a,a)") "usage : ", TRIM(keyword%usage)
527 : END IF
528 19 : IF (level > 2) THEN
529 19 : WRITE (unit_nr, "(a)") "description : "
530 19 : CALL print_message(TRIM(a2s(keyword%description)), unit_nr, 0, 0, 0)
531 19 : IF (level > 3) THEN
532 0 : SELECT CASE (keyword%type_of_var)
533 : CASE (logical_t)
534 0 : IF (keyword%n_var == -1) THEN
535 0 : WRITE (unit_nr, "(' A list of logicals is expected')")
536 0 : ELSE IF (keyword%n_var == 1) THEN
537 0 : WRITE (unit_nr, "(' A logical is expected')")
538 : ELSE
539 0 : WRITE (unit_nr, "(i6,' logicals are expected')") keyword%n_var
540 : END IF
541 0 : WRITE (unit_nr, "(' (T,TRUE,YES,ON) and (F,FALSE,NO,OFF) are synonyms')")
542 : CASE (integer_t)
543 0 : IF (keyword%n_var == -1) THEN
544 0 : WRITE (unit_nr, "(' A list of integers is expected')")
545 0 : ELSE IF (keyword%n_var == 1) THEN
546 0 : WRITE (unit_nr, "(' An integer is expected')")
547 : ELSE
548 0 : WRITE (unit_nr, "(i6,' integers are expected')") keyword%n_var
549 : END IF
550 : CASE (real_t)
551 0 : IF (keyword%n_var == -1) THEN
552 0 : WRITE (unit_nr, "(' A list of reals is expected')")
553 0 : ELSE IF (keyword%n_var == 1) THEN
554 0 : WRITE (unit_nr, "(' A real is expected')")
555 : ELSE
556 0 : WRITE (unit_nr, "(i6,' reals are expected')") keyword%n_var
557 : END IF
558 0 : IF (ASSOCIATED(keyword%unit)) THEN
559 0 : c_string = cp_unit_desc(keyword%unit, accept_undefined=.TRUE.)
560 : WRITE (unit_nr, "('the default unit of measure is ',a)") &
561 0 : TRIM(c_string)
562 : END IF
563 : CASE (char_t)
564 0 : IF (keyword%n_var == -1) THEN
565 0 : WRITE (unit_nr, "(' A list of words is expected')")
566 0 : ELSE IF (keyword%n_var == 1) THEN
567 0 : WRITE (unit_nr, "(' A word is expected')")
568 : ELSE
569 0 : WRITE (unit_nr, "(i6,' words are expected')") keyword%n_var
570 : END IF
571 : CASE (lchar_t)
572 0 : WRITE (unit_nr, "(' A string is expected')")
573 : CASE (enum_t)
574 0 : IF (keyword%n_var == -1) THEN
575 0 : WRITE (unit_nr, "(' A list of keywords is expected')")
576 0 : ELSE IF (keyword%n_var == 1) THEN
577 0 : WRITE (unit_nr, "(' A keyword is expected')")
578 : ELSE
579 0 : WRITE (unit_nr, "(i6,' keywords are expected')") keyword%n_var
580 : END IF
581 : CASE (no_t)
582 0 : WRITE (unit_nr, "(' Non-standard type.')")
583 : CASE default
584 0 : CPABORT("")
585 : END SELECT
586 : END IF
587 19 : IF (keyword%type_of_var == enum_t) THEN
588 2 : IF (level > 3) THEN
589 0 : WRITE (unit_nr, "(' valid keywords:')")
590 0 : DO i = 1, SIZE(keyword%enum%c_vals)
591 0 : c_string = keyword%enum%c_vals(i)
592 0 : IF (LEN_TRIM(a2s(keyword%enum%desc(i)%chars)) > 0) THEN
593 : WRITE (unit_nr, "(' - ',a,' : ',a,'.')") &
594 0 : TRIM(c_string), TRIM(a2s(keyword%enum%desc(i)%chars))
595 : ELSE
596 0 : WRITE (unit_nr, "(' - ',a)") TRIM(c_string)
597 : END IF
598 : END DO
599 : ELSE
600 2 : WRITE (unit_nr, "(' valid keywords:')", advance='NO')
601 2 : l = 17
602 18 : DO i = 1, SIZE(keyword%enum%c_vals)
603 16 : c_string = keyword%enum%c_vals(i)
604 16 : IF (l + LEN_TRIM(c_string) > 72 .AND. l > 14) THEN
605 0 : WRITE (unit_nr, "(/,' ')", advance='NO')
606 0 : l = 4
607 : END IF
608 16 : WRITE (unit_nr, "(' ',a)", advance='NO') TRIM(c_string)
609 18 : l = LEN_TRIM(c_string) + 3
610 : END DO
611 2 : WRITE (unit_nr, "()")
612 : END IF
613 2 : IF (.NOT. keyword%enum%strict) THEN
614 0 : WRITE (unit_nr, "(' other integer values are also accepted.')")
615 : END IF
616 : END IF
617 19 : IF (ASSOCIATED(keyword%default_value) .AND. keyword%type_of_var /= no_t) THEN
618 17 : WRITE (unit_nr, "('default_value : ')", advance="NO")
619 17 : CALL val_write(keyword%default_value, unit_nr=unit_nr)
620 : END IF
621 19 : IF (ASSOCIATED(keyword%lone_keyword_value) .AND. keyword%type_of_var /= no_t) THEN
622 3 : WRITE (unit_nr, "('lone_keyword : ')", advance="NO")
623 3 : CALL val_write(keyword%lone_keyword_value, unit_nr=unit_nr)
624 : END IF
625 19 : IF (keyword%repeats) THEN
626 0 : WRITE (unit_nr, "(' and it can be repeated more than once')", advance="NO")
627 : END IF
628 19 : WRITE (unit_nr, "()")
629 19 : IF (SIZE(keyword%names) > 1) THEN
630 1 : WRITE (unit_nr, "(a)", advance="NO") "variants : "
631 3 : DO i = 2, SIZE(keyword%names)
632 3 : WRITE (unit_nr, "(a,' ')", advance="NO") keyword%names(i)
633 : END DO
634 1 : WRITE (unit_nr, "()")
635 : END IF
636 : END IF
637 : END IF
638 19 : END SUBROUTINE keyword_describe
639 :
640 : ! **************************************************************************************************
641 : !> \brief Prints a description of a keyword in XML format
642 : !> \param keyword The keyword to describe
643 : !> \param level ...
644 : !> \param unit_number Number of the output unit
645 : !> \author Matthias Krack
646 : ! **************************************************************************************************
647 0 : SUBROUTINE write_keyword_xml(keyword, level, unit_number)
648 :
649 : TYPE(keyword_type), POINTER :: keyword
650 : INTEGER, INTENT(IN) :: level, unit_number
651 :
652 : CHARACTER(LEN=1000) :: string
653 : CHARACTER(LEN=3) :: removed, repeats
654 : CHARACTER(LEN=8) :: short_string
655 : INTEGER :: i, l0, l1, l2, l3, l4
656 :
657 0 : CPASSERT(ASSOCIATED(keyword))
658 0 : CPASSERT(keyword%ref_count > 0)
659 :
660 : ! Indentation for current level, next level, etc.
661 :
662 0 : l0 = level
663 0 : l1 = level + 1
664 0 : l2 = level + 2
665 0 : l3 = level + 3
666 0 : l4 = level + 4
667 :
668 0 : IF (keyword%repeats) THEN
669 0 : repeats = "yes"
670 : ELSE
671 0 : repeats = "no "
672 : END IF
673 :
674 0 : IF (keyword%removed) THEN
675 0 : removed = "yes"
676 : ELSE
677 0 : removed = "no "
678 : END IF
679 :
680 : ! Write (special) keyword element
681 :
682 0 : IF (keyword%names(1) == "_SECTION_PARAMETERS_") THEN
683 0 : WRITE (UNIT=unit_number, FMT="(A)") &
684 : REPEAT(" ", l0)//"<SECTION_PARAMETERS repeats="""//TRIM(repeats)// &
685 0 : """ removed="""//TRIM(removed)//""">", &
686 0 : REPEAT(" ", l1)//"<NAME type=""default"">SECTION_PARAMETERS</NAME>"
687 0 : ELSE IF (keyword%names(1) == "_DEFAULT_KEYWORD_") THEN
688 0 : WRITE (UNIT=unit_number, FMT="(A)") &
689 0 : REPEAT(" ", l0)//"<DEFAULT_KEYWORD repeats="""//TRIM(repeats)//""">", &
690 0 : REPEAT(" ", l1)//"<NAME type=""default"">DEFAULT_KEYWORD</NAME>"
691 : ELSE
692 0 : WRITE (UNIT=unit_number, FMT="(A)") &
693 : REPEAT(" ", l0)//"<KEYWORD repeats="""//TRIM(repeats)// &
694 0 : """ removed="""//TRIM(removed)//""">", &
695 : REPEAT(" ", l1)//"<NAME type=""default"">"// &
696 0 : TRIM(keyword%names(1))//"</NAME>"
697 : END IF
698 :
699 0 : DO i = 2, SIZE(keyword%names)
700 0 : WRITE (UNIT=unit_number, FMT="(A)") &
701 : REPEAT(" ", l1)//"<NAME type=""alias"">"// &
702 0 : TRIM(keyword%names(i))//"</NAME>"
703 : END DO
704 :
705 0 : SELECT CASE (keyword%type_of_var)
706 : CASE (logical_t)
707 0 : WRITE (UNIT=unit_number, FMT="(A)") &
708 0 : REPEAT(" ", l1)//"<DATA_TYPE kind=""logical"">"
709 : CASE (integer_t)
710 0 : WRITE (UNIT=unit_number, FMT="(A)") &
711 0 : REPEAT(" ", l1)//"<DATA_TYPE kind=""integer"">"
712 : CASE (real_t)
713 0 : WRITE (UNIT=unit_number, FMT="(A)") &
714 0 : REPEAT(" ", l1)//"<DATA_TYPE kind=""real"">"
715 : CASE (char_t)
716 0 : WRITE (UNIT=unit_number, FMT="(A)") &
717 0 : REPEAT(" ", l1)//"<DATA_TYPE kind=""word"">"
718 : CASE (lchar_t)
719 0 : WRITE (UNIT=unit_number, FMT="(A)") &
720 0 : REPEAT(" ", l1)//"<DATA_TYPE kind=""string"">"
721 : CASE (enum_t)
722 0 : WRITE (UNIT=unit_number, FMT="(A)") &
723 0 : REPEAT(" ", l1)//"<DATA_TYPE kind=""keyword"">"
724 0 : IF (keyword%enum%strict) THEN
725 0 : WRITE (UNIT=unit_number, FMT="(A)") &
726 0 : REPEAT(" ", l2)//"<ENUMERATION strict=""yes"">"
727 : ELSE
728 0 : WRITE (UNIT=unit_number, FMT="(A)") &
729 0 : REPEAT(" ", l2)//"<ENUMERATION strict=""no"">"
730 : END IF
731 0 : DO i = 1, SIZE(keyword%enum%c_vals)
732 0 : WRITE (UNIT=unit_number, FMT="(A)") &
733 0 : REPEAT(" ", l3)//"<ITEM>", &
734 : REPEAT(" ", l4)//"<NAME>"// &
735 0 : TRIM(ADJUSTL(substitute_special_xml_tokens(keyword%enum%c_vals(i))))//"</NAME>", &
736 : REPEAT(" ", l4)//"<DESCRIPTION>"// &
737 : TRIM(ADJUSTL(substitute_special_xml_tokens(a2s(keyword%enum%desc(i)%chars)))) &
738 0 : //"</DESCRIPTION>", REPEAT(" ", l3)//"</ITEM>"
739 : END DO
740 0 : WRITE (UNIT=unit_number, FMT="(A)") REPEAT(" ", l2)//"</ENUMERATION>"
741 : CASE (no_t)
742 0 : WRITE (UNIT=unit_number, FMT="(A)") &
743 0 : REPEAT(" ", l1)//"<DATA_TYPE kind=""non-standard type"">"
744 : CASE DEFAULT
745 0 : CPABORT("")
746 : END SELECT
747 :
748 0 : short_string = ""
749 0 : WRITE (UNIT=short_string, FMT="(I8)") keyword%n_var
750 0 : WRITE (UNIT=unit_number, FMT="(A)") &
751 0 : REPEAT(" ", l2)//"<N_VAR>"//TRIM(ADJUSTL(short_string))//"</N_VAR>", &
752 0 : REPEAT(" ", l1)//"</DATA_TYPE>"
753 :
754 : WRITE (UNIT=unit_number, FMT="(A)") REPEAT(" ", l1)//"<USAGE>"// &
755 : TRIM(substitute_special_xml_tokens(keyword%usage)) &
756 0 : //"</USAGE>"
757 :
758 : WRITE (UNIT=unit_number, FMT="(A)") REPEAT(" ", l1)//"<DESCRIPTION>"// &
759 : TRIM(substitute_special_xml_tokens(a2s(keyword%description))) &
760 0 : //"</DESCRIPTION>"
761 :
762 0 : IF (ALLOCATED(keyword%deprecation_notice)) &
763 : WRITE (UNIT=unit_number, FMT="(A)") REPEAT(" ", l1)//"<DEPRECATION_NOTICE>"// &
764 : TRIM(substitute_special_xml_tokens(keyword%deprecation_notice)) &
765 0 : //"</DEPRECATION_NOTICE>"
766 :
767 0 : IF (ASSOCIATED(keyword%default_value) .AND. &
768 : (keyword%type_of_var /= no_t)) THEN
769 0 : IF (ASSOCIATED(keyword%unit)) THEN
770 : CALL val_write_internal(val=keyword%default_value, &
771 : string=string, &
772 0 : unit=keyword%unit)
773 : ELSE
774 : CALL val_write_internal(val=keyword%default_value, &
775 0 : string=string)
776 : END IF
777 0 : CALL compress(string)
778 : WRITE (UNIT=unit_number, FMT="(A)") &
779 : REPEAT(" ", l1)//"<DEFAULT_VALUE>"// &
780 0 : TRIM(ADJUSTL(substitute_special_xml_tokens(string)))//"</DEFAULT_VALUE>"
781 : END IF
782 :
783 0 : IF (ASSOCIATED(keyword%unit)) THEN
784 0 : string = cp_unit_desc(keyword%unit, accept_undefined=.TRUE.)
785 : WRITE (UNIT=unit_number, FMT="(A)") &
786 : REPEAT(" ", l1)//"<DEFAULT_UNIT>"// &
787 0 : TRIM(ADJUSTL(string))//"</DEFAULT_UNIT>"
788 : END IF
789 :
790 0 : IF (ASSOCIATED(keyword%lone_keyword_value) .AND. &
791 : (keyword%type_of_var /= no_t)) THEN
792 : CALL val_write_internal(val=keyword%lone_keyword_value, &
793 0 : string=string)
794 : WRITE (UNIT=unit_number, FMT="(A)") &
795 : REPEAT(" ", l1)//"<LONE_KEYWORD_VALUE>"// &
796 0 : TRIM(ADJUSTL(substitute_special_xml_tokens(string)))//"</LONE_KEYWORD_VALUE>"
797 : END IF
798 :
799 0 : IF (ASSOCIATED(keyword%citations)) THEN
800 0 : DO i = 1, SIZE(keyword%citations, 1)
801 0 : short_string = ""
802 0 : WRITE (UNIT=short_string, FMT="(I8)") keyword%citations(i)
803 : WRITE (UNIT=unit_number, FMT="(A)") &
804 0 : REPEAT(" ", l1)//"<REFERENCE>", &
805 0 : REPEAT(" ", l2)//"<NAME>"//TRIM(get_citation_key(keyword%citations(i)))//"</NAME>", &
806 0 : REPEAT(" ", l2)//"<NUMBER>"//TRIM(ADJUSTL(short_string))//"</NUMBER>", &
807 0 : REPEAT(" ", l1)//"</REFERENCE>"
808 : END DO
809 : END IF
810 :
811 : WRITE (UNIT=unit_number, FMT="(A)") &
812 0 : REPEAT(" ", l1)//"<LOCATION>"//TRIM(keyword%location)//"</LOCATION>"
813 :
814 : ! Close (special) keyword section
815 :
816 0 : IF (keyword%names(1) == "_SECTION_PARAMETERS_") THEN
817 0 : WRITE (UNIT=unit_number, FMT="(A)") &
818 0 : REPEAT(" ", l0)//"</SECTION_PARAMETERS>"
819 0 : ELSE IF (keyword%names(1) == "_DEFAULT_KEYWORD_") THEN
820 0 : WRITE (UNIT=unit_number, FMT="(A)") &
821 0 : REPEAT(" ", l0)//"</DEFAULT_KEYWORD>"
822 : ELSE
823 0 : WRITE (UNIT=unit_number, FMT="(A)") &
824 0 : REPEAT(" ", l0)//"</KEYWORD>"
825 : END IF
826 :
827 0 : END SUBROUTINE write_keyword_xml
828 :
829 : ! **************************************************************************************************
830 : !> \brief ...
831 : !> \param keyword ...
832 : !> \param unknown_string ...
833 : !> \param location_string ...
834 : !> \param matching_rank ...
835 : !> \param matching_string ...
836 : !> \param bonus ...
837 : ! **************************************************************************************************
838 0 : SUBROUTINE keyword_typo_match(keyword, unknown_string, location_string, matching_rank, matching_string, bonus)
839 :
840 : TYPE(keyword_type), POINTER :: keyword
841 : CHARACTER(LEN=*) :: unknown_string, location_string
842 : INTEGER, DIMENSION(:), INTENT(INOUT) :: matching_rank
843 : CHARACTER(LEN=*), DIMENSION(:), INTENT(INOUT) :: matching_string
844 : INTEGER, INTENT(IN) :: bonus
845 :
846 0 : CHARACTER(LEN=LEN(matching_string(1))) :: line
847 : INTEGER :: i, imatch, imax, irank, j, k
848 :
849 0 : CPASSERT(ASSOCIATED(keyword))
850 0 : CPASSERT(keyword%ref_count > 0)
851 :
852 0 : DO i = 1, SIZE(keyword%names)
853 0 : imatch = typo_match(TRIM(keyword%names(i)), TRIM(unknown_string))
854 0 : IF (imatch > 0) THEN
855 0 : imatch = imatch + bonus
856 0 : WRITE (line, '(T2,A)') " keyword "//TRIM(keyword%names(i))//" in section "//TRIM(location_string)
857 0 : imax = SIZE(matching_rank, 1)
858 0 : irank = imax + 1
859 0 : DO k = imax, 1, -1
860 0 : IF (imatch > matching_rank(k)) irank = k
861 : END DO
862 0 : IF (irank <= imax) THEN
863 0 : matching_rank(irank + 1:imax) = matching_rank(irank:imax - 1)
864 0 : matching_string(irank + 1:imax) = matching_string(irank:imax - 1)
865 0 : matching_rank(irank) = imatch
866 0 : matching_string(irank) = line
867 : END IF
868 : END IF
869 :
870 0 : IF (keyword%type_of_var == enum_t) THEN
871 0 : DO j = 1, SIZE(keyword%enum%c_vals)
872 0 : imatch = typo_match(TRIM(keyword%enum%c_vals(j)), TRIM(unknown_string))
873 0 : IF (imatch > 0) THEN
874 0 : imatch = imatch + bonus
875 : WRITE (line, '(T2,A)') " enum "//TRIM(keyword%enum%c_vals(j))// &
876 : " in section "//TRIM(location_string)// &
877 0 : " for keyword "//TRIM(keyword%names(i))
878 0 : imax = SIZE(matching_rank, 1)
879 0 : irank = imax + 1
880 0 : DO k = imax, 1, -1
881 0 : IF (imatch > matching_rank(k)) irank = k
882 : END DO
883 0 : IF (irank <= imax) THEN
884 0 : matching_rank(irank + 1:imax) = matching_rank(irank:imax - 1)
885 0 : matching_string(irank + 1:imax) = matching_string(irank:imax - 1)
886 0 : matching_rank(irank) = imatch
887 0 : matching_string(irank) = line
888 : END IF
889 : END IF
890 : END DO
891 : END IF
892 : END DO
893 :
894 0 : END SUBROUTINE keyword_typo_match
895 :
896 0 : END MODULE input_keyword_types
|