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 an enumeration, i.e. a mapping between integers and strings
10 : !> \par History
11 : !> 08.2004 created [fawzi]
12 : !> \author fawzi
13 : ! **************************************************************************************************
14 : MODULE input_enumeration_types
15 :
16 : USE cp_log_handling, ONLY: cp_to_string
17 : USE kinds, ONLY: default_string_length
18 : USE string_utilities, ONLY: a2s,&
19 : uppercase
20 : #include "../base/base_uses.f90"
21 :
22 : IMPLICIT NONE
23 : PRIVATE
24 :
25 : LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
26 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'input_enumeration_types'
27 :
28 : PUBLIC :: enumeration_type
29 : PUBLIC :: enum_create, enum_retain, enum_release, enum_i2c, enum_c2i
30 :
31 : ! **************************************************************************************************
32 : !> \brief represents an enumaration, i.e. a mapping between strings and numbers
33 : !> \param ref_count reference count
34 : !> \param c_vals string values
35 : !> \param i_vals integer values
36 : !> \param strict if integer values not in the list should be accepted
37 : !> \author fawzi
38 : ! **************************************************************************************************
39 : TYPE char_array
40 : CHARACTER, DIMENSION(:), POINTER :: chars => Null()
41 : END TYPE char_array
42 :
43 : TYPE enumeration_type
44 : INTEGER :: ref_count = 0
45 : CHARACTER(len=default_string_length), DIMENSION(:), POINTER :: c_vals => NULL()
46 : TYPE(char_array), DIMENSION(:), POINTER :: desc => Null()
47 : INTEGER, DIMENSION(:), POINTER :: i_vals => NULL()
48 : LOGICAL :: strict = .FALSE.
49 : END TYPE enumeration_type
50 :
51 : CONTAINS
52 :
53 : ! **************************************************************************************************
54 : !> \brief creates an enumeration
55 : !> \param enum the enumeration to be created
56 : !> \param c_vals string values
57 : !> \param i_vals integer values
58 : !> \param desc ...
59 : !> \param strict if integer values not in the list should be accepted,
60 : !> defaults defaults to true
61 : !> \author fawzi
62 : ! **************************************************************************************************
63 22688509 : SUBROUTINE enum_create(enum, c_vals, i_vals, desc, strict)
64 : TYPE(enumeration_type), POINTER :: enum
65 : CHARACTER(len=*), DIMENSION(:), INTENT(in) :: c_vals
66 : INTEGER, DIMENSION(:), INTENT(in) :: i_vals
67 : CHARACTER(len=*), DIMENSION(:), INTENT(in), &
68 : OPTIONAL :: desc
69 : LOGICAL, INTENT(in), OPTIONAL :: strict
70 :
71 : INTEGER :: i, j, n
72 :
73 22688509 : CPASSERT(.NOT. ASSOCIATED(enum))
74 22688509 : CPASSERT(SIZE(c_vals) == SIZE(i_vals))
75 22688509 : ALLOCATE (enum)
76 22688509 : enum%ref_count = 1
77 68065527 : ALLOCATE (enum%c_vals(SIZE(c_vals)))
78 127054267 : DO i = 1, SIZE(enum%c_vals)
79 104365758 : CPASSERT(LEN_TRIM(c_vals(i)) > 0)
80 104365758 : enum%c_vals(i) = c_vals(i)
81 127054267 : CALL uppercase(enum%c_vals(i))
82 : END DO
83 68065527 : ALLOCATE (enum%i_vals(SIZE(i_vals)))
84 127054267 : enum%i_vals = i_vals
85 22688509 : enum%strict = .TRUE.
86 22688509 : IF (PRESENT(strict)) enum%strict = strict
87 172431285 : ALLOCATE (enum%desc(SIZE(c_vals)))
88 22688509 : IF (PRESENT(desc)) THEN
89 14267275 : CPASSERT(SIZE(enum%desc) == SIZE(desc))
90 64492369 : DO i = 1, SIZE(enum%desc)
91 50225094 : n = LEN_TRIM(desc(i))
92 150675282 : ALLOCATE (enum%desc(i)%chars(n))
93 2475823339 : DO j = 1, n
94 2461556064 : enum%desc(i)%chars(j) = desc(i) (j:j)
95 : END DO
96 : END DO
97 : ELSE
98 62561898 : DO i = 1, SIZE(enum%desc)
99 54140664 : ALLOCATE (enum%desc(i)%chars(1))
100 116702562 : enum%desc(i)%chars(1:1) = ' '
101 : END DO
102 : END IF
103 22688509 : END SUBROUTINE enum_create
104 :
105 : ! **************************************************************************************************
106 : !> \brief retains the given enumeration
107 : !> \param enum the obect to retain
108 : !> \author fawzi
109 : ! **************************************************************************************************
110 29251454 : SUBROUTINE enum_retain(enum)
111 : TYPE(enumeration_type), POINTER :: enum
112 :
113 29251454 : CPASSERT(ASSOCIATED(enum))
114 29251454 : CPASSERT(enum%ref_count > 0)
115 29251454 : enum%ref_count = enum%ref_count + 1
116 29251454 : END SUBROUTINE enum_retain
117 :
118 : ! **************************************************************************************************
119 : !> \brief releases the given enumeration
120 : !> \param enum the obect to release
121 : !> \author fawzi
122 : ! **************************************************************************************************
123 1791393488 : SUBROUTINE enum_release(enum)
124 : TYPE(enumeration_type), POINTER :: enum
125 :
126 : INTEGER :: i
127 :
128 1791393488 : IF (ASSOCIATED(enum)) THEN
129 51939963 : CPASSERT(enum%ref_count > 0)
130 51939963 : enum%ref_count = enum%ref_count - 1
131 51939963 : IF (enum%ref_count == 0) THEN
132 22688509 : DEALLOCATE (enum%c_vals)
133 22688509 : DEALLOCATE (enum%i_vals)
134 127054267 : DO i = 1, SIZE(enum%desc)
135 127054267 : DEALLOCATE (enum%desc(i)%chars)
136 : END DO
137 22688509 : DEALLOCATE (enum%desc)
138 22688509 : DEALLOCATE (enum)
139 : END IF
140 : END IF
141 1791393488 : NULLIFY (enum)
142 1791393488 : END SUBROUTINE enum_release
143 :
144 : ! **************************************************************************************************
145 : !> \brief maps an integer to a string
146 : !> \param enum the enumeration to use for the mapping
147 : !> \param i the value to map
148 : !> \return ...
149 : !> \author fawzi
150 : ! **************************************************************************************************
151 160559 : FUNCTION enum_i2c(enum, i) RESULT(res)
152 : TYPE(enumeration_type), POINTER :: enum
153 : INTEGER, INTENT(in) :: i
154 : CHARACTER(len=default_string_length) :: res
155 :
156 : INTEGER :: j
157 : LOGICAL :: found
158 :
159 160559 : CPASSERT(ASSOCIATED(enum))
160 160559 : CPASSERT(enum%ref_count > 0)
161 160559 : res = " "
162 160559 : found = .FALSE.
163 501190 : DO j = 1, SIZE(enum%i_vals)
164 501190 : IF (enum%i_vals(j) == i) THEN
165 160559 : res = enum%c_vals(j)
166 : found = .TRUE.
167 : EXIT
168 : END IF
169 : END DO
170 : IF (.NOT. found) THEN
171 0 : IF (enum%strict) THEN
172 0 : DO j = 1, SIZE(enum%desc)
173 0 : PRINT *, TRIM(a2s(enum%desc(j)%chars))
174 0 : PRINT *, TRIM(enum%c_vals(j))
175 : END DO
176 0 : PRINT *, enum%i_vals
177 : END IF
178 0 : IF (enum%strict) &
179 0 : CPABORT("invalid value for enumeration:"//cp_to_string(i))
180 0 : res = ADJUSTL(cp_to_string(i))
181 : END IF
182 160559 : END FUNCTION enum_i2c
183 :
184 : ! **************************************************************************************************
185 : !> \brief maps a string to an integer
186 : !> \param enum the enumeration to use for the mapping
187 : !> \param c the value to map
188 : !> \return ...
189 : !> \author fawzi
190 : ! **************************************************************************************************
191 94804 : FUNCTION enum_c2i(enum, c) RESULT(res)
192 : TYPE(enumeration_type), POINTER :: enum
193 : CHARACTER(len=*), INTENT(in) :: c
194 : INTEGER :: res
195 :
196 : CHARACTER(len=default_string_length) :: upc
197 : INTEGER :: iostat, j
198 : LOGICAL :: found
199 :
200 0 : CPASSERT(ASSOCIATED(enum))
201 94804 : CPASSERT(enum%ref_count > 0)
202 94804 : upc = TRIM(ADJUSTL(c)) !MK Ignore leading and trailing blanks
203 94804 : CALL uppercase(upc)
204 94804 : found = .FALSE.
205 349760 : DO j = 1, SIZE(enum%c_vals)
206 349760 : IF (enum%c_vals(j) == upc) THEN
207 94804 : res = enum%i_vals(j)
208 : found = .TRUE.
209 : EXIT
210 : END IF
211 : END DO
212 :
213 : IF (.NOT. found) THEN
214 0 : IF (enum%strict) &
215 0 : CPABORT("invalid value for enumeration:"//TRIM(c))
216 0 : READ (c, "(i10)", iostat=iostat) res
217 0 : IF (iostat /= 0) &
218 0 : CPABORT("invalid value for enumeration2:"//TRIM(c))
219 : END IF
220 94804 : END FUNCTION enum_c2i
221 :
222 0 : END MODULE input_enumeration_types
|