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 Collection of subroutine needed for topology related things
10 : !> \par History
11 : !> Teodor Laino 09.2006 - Major rewriting with linear scaling routines
12 : ! **************************************************************************************************
13 : MODULE topology_generate_util
14 : USE atomic_kind_types, ONLY: atomic_kind_type,&
15 : deallocate_atomic_kind_set,&
16 : set_atomic_kind
17 : USE cell_types, ONLY: pbc
18 : USE cp_log_handling, ONLY: cp_get_default_logger,&
19 : cp_logger_get_default_io_unit,&
20 : cp_logger_type,&
21 : cp_to_string
22 : USE cp_output_handling, ONLY: cp_print_key_finished_output,&
23 : cp_print_key_unit_nr
24 : USE cp_units, ONLY: cp_unit_to_cp2k
25 : USE fist_neighbor_list_types, ONLY: fist_neighbor_deallocate,&
26 : fist_neighbor_type
27 : USE fist_neighbor_lists, ONLY: build_fist_neighbor_lists
28 : USE input_constants, ONLY: do_add,&
29 : do_bondparm_covalent,&
30 : do_bondparm_vdw,&
31 : do_conn_off,&
32 : do_conn_user,&
33 : do_remove
34 : USE input_section_types, ONLY: section_vals_get,&
35 : section_vals_get_subs_vals,&
36 : section_vals_type,&
37 : section_vals_val_get
38 : USE kinds, ONLY: default_string_length,&
39 : dp
40 : USE memory_utilities, ONLY: reallocate
41 : USE message_passing, ONLY: mp_para_env_type
42 : USE particle_types, ONLY: allocate_particle_set,&
43 : deallocate_particle_set,&
44 : particle_type
45 : USE periodic_table, ONLY: get_ptable_info
46 : USE qmmm_types_low, ONLY: qmmm_env_mm_type
47 : USE string_table, ONLY: id2str,&
48 : s2s,&
49 : str2id
50 : USE string_utilities, ONLY: integer_to_string,&
51 : uppercase
52 : USE topology_types, ONLY: atom_info_type,&
53 : connectivity_info_type,&
54 : topology_parameters_type
55 : USE topology_util, ONLY: array1_list_type,&
56 : array2_list_type,&
57 : find_molecule,&
58 : give_back_molecule,&
59 : reorder_list_array,&
60 : reorder_structure
61 : USE util, ONLY: find_boundary,&
62 : sort
63 : #include "./base/base_uses.f90"
64 :
65 : IMPLICIT NONE
66 :
67 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'topology_generate_util'
68 :
69 : PRIVATE
70 : LOGICAL, PARAMETER :: debug_this_module = .FALSE.
71 :
72 : PUBLIC :: topology_generate_bend, &
73 : topology_generate_bond, &
74 : topology_generate_dihe, &
75 : topology_generate_impr, &
76 : topology_generate_onfo, &
77 : topology_generate_ub, &
78 : topology_generate_molecule, &
79 : topology_generate_molname
80 :
81 : CONTAINS
82 :
83 : ! **************************************************************************************************
84 : !> \brief Generates molnames: useful when the connectivity on file does not
85 : !> provide them
86 : !> \param conn_info ...
87 : !> \param natom ...
88 : !> \param natom_prev ...
89 : !> \param nbond_prev ...
90 : !> \param id_molname ...
91 : !> \author Teodoro Laino [tlaino] - University of Zurich 10.2008
92 : ! **************************************************************************************************
93 22 : SUBROUTINE topology_generate_molname(conn_info, natom, natom_prev, nbond_prev, &
94 22 : id_molname)
95 : TYPE(connectivity_info_type), POINTER :: conn_info
96 : INTEGER, INTENT(IN) :: natom, natom_prev, nbond_prev
97 : INTEGER, DIMENSION(:), INTENT(INOUT) :: id_molname
98 :
99 : CHARACTER(LEN=default_string_length), PARAMETER :: basename = "MOL"
100 :
101 : CHARACTER(LEN=default_string_length) :: molname
102 : INTEGER :: i, id_undef, n, nmol
103 : LOGICAL :: check
104 22 : TYPE(array1_list_type), ALLOCATABLE, DIMENSION(:) :: atom_bond_list
105 :
106 : ! convert a simple list of bonds to a list of bonds per atom
107 : ! (each bond is present in the forward and backward direction
108 :
109 78904 : ALLOCATE (atom_bond_list(natom))
110 78860 : DO i = 1, natom
111 78860 : ALLOCATE (atom_bond_list(i)%array1(0))
112 : END DO
113 22 : n = 0
114 22 : IF (ASSOCIATED(conn_info%bond_a)) n = SIZE(conn_info%bond_a) - nbond_prev
115 : CALL reorder_structure(atom_bond_list, conn_info%bond_a(nbond_prev + 1:) - natom_prev, &
116 114378 : conn_info%bond_b(nbond_prev + 1:) - natom_prev, n)
117 :
118 22 : nmol = 0
119 22 : id_undef = str2id(s2s("__UNDEF__"))
120 78882 : check = ALL(id_molname == id_undef) .OR. ALL(id_molname /= id_undef)
121 22 : CPASSERT(check)
122 78860 : DO i = 1, natom
123 78860 : IF (id_molname(i) == id_undef) THEN
124 21954 : molname = TRIM(basename)//ADJUSTL(cp_to_string(nmol))
125 21954 : CALL generate_molname_low(i, atom_bond_list, molname, id_molname)
126 21954 : nmol = nmol + 1
127 : END IF
128 : END DO
129 78860 : DO i = 1, natom
130 78860 : DEALLOCATE (atom_bond_list(i)%array1)
131 : END DO
132 22 : DEALLOCATE (atom_bond_list)
133 :
134 22 : END SUBROUTINE topology_generate_molname
135 :
136 : ! **************************************************************************************************
137 : !> \brief Generates molnames: useful when the connectivity on file does not
138 : !> provide them
139 : !> \param i ...
140 : !> \param atom_bond_list ...
141 : !> \param molname ...
142 : !> \param id_molname ...
143 : !> \author Teodoro Laino [tlaino] - University of Zurich 10.2008
144 : ! **************************************************************************************************
145 79132 : RECURSIVE SUBROUTINE generate_molname_low(i, atom_bond_list, molname, id_molname)
146 : INTEGER, INTENT(IN) :: i
147 : TYPE(array1_list_type), DIMENSION(:) :: atom_bond_list
148 : CHARACTER(LEN=default_string_length), INTENT(IN) :: molname
149 : INTEGER, DIMENSION(:), INTENT(INOUT) :: id_molname
150 :
151 : INTEGER :: j, k
152 :
153 : IF (debug_this_module) THEN
154 : WRITE (*, *) "Entered with :", i
155 : WRITE (*, *) TRIM(molname)//": entering with i:", i, " full series to test:: ", atom_bond_list(i)%array1
156 : IF ((TRIM(id2str(id_molname(i))) /= "__UNDEF__") .AND. &
157 : (TRIM(id2str(id_molname(i))) /= TRIM(molname))) THEN
158 : WRITE (*, *) "Atom (", i, ") has already a molecular name assigned ! ("//TRIM(id2str(id_molname(i)))//")."
159 : WRITE (*, *) "New molecular name would be: ("//TRIM(molname)//")."
160 : WRITE (*, *) "Detecting something wrong in the molecular setup!"
161 : CPABORT("")
162 : END IF
163 : END IF
164 79132 : id_molname(i) = str2id(molname)
165 194494 : DO j = 1, SIZE(atom_bond_list(i)%array1)
166 115362 : k = atom_bond_list(i)%array1(j)
167 : IF (debug_this_module) WRITE (*, *) "entering with i:", i, "testing :", k
168 115362 : IF (k == -1) CYCLE
169 57178 : atom_bond_list(i)%array1(j) = -1
170 128560 : WHERE (atom_bond_list(k)%array1 == i) atom_bond_list(k)%array1 = -1
171 194494 : CALL generate_molname_low(k, atom_bond_list, molname, id_molname)
172 : END DO
173 79132 : END SUBROUTINE generate_molname_low
174 :
175 : ! **************************************************************************************************
176 : !> \brief Use information from bond list to generate molecule. (ie clustering)
177 : !> \param topology ...
178 : !> \param qmmm ...
179 : !> \param qmmm_env ...
180 : !> \param subsys_section ...
181 : ! **************************************************************************************************
182 10274 : SUBROUTINE topology_generate_molecule(topology, qmmm, qmmm_env, subsys_section)
183 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
184 : LOGICAL, INTENT(in), OPTIONAL :: qmmm
185 : TYPE(qmmm_env_mm_type), OPTIONAL, POINTER :: qmmm_env
186 : TYPE(section_vals_type), POINTER :: subsys_section
187 :
188 : CHARACTER(len=*), PARAMETER :: routineN = 'topology_generate_molecule'
189 : INTEGER, PARAMETER :: nblock = 100
190 :
191 : INTEGER :: atom_in_kind, atom_in_mol, first, handle, handle2, i, iatm, iatom, iend, ifirst, &
192 : ilast, inum, istart, itype, iw, j, jump1, jump2, last, max_mol_num, mol_num, mol_res, &
193 : mol_typ, myind, N, natom, nlocl, ntype, resid
194 10274 : INTEGER, DIMENSION(:), POINTER :: qm_atom_index, wrk1, wrk2
195 : LOGICAL :: do_again, found, my_qmmm
196 10274 : TYPE(array1_list_type), ALLOCATABLE, DIMENSION(:) :: atom_bond_list
197 : TYPE(atom_info_type), POINTER :: atom_info
198 : TYPE(connectivity_info_type), POINTER :: conn_info
199 : TYPE(cp_logger_type), POINTER :: logger
200 :
201 10274 : NULLIFY (logger)
202 20548 : logger => cp_get_default_logger()
203 : iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/UTIL_INFO", &
204 10274 : extension=".subsysLog")
205 10274 : CALL timeset(routineN, handle)
206 10274 : NULLIFY (qm_atom_index)
207 10274 : NULLIFY (wrk1)
208 10274 : NULLIFY (wrk2)
209 :
210 10274 : atom_info => topology%atom_info
211 10274 : conn_info => topology%conn_info
212 : !
213 : ! QM/MM coordinate_control
214 : !
215 10274 : my_qmmm = .FALSE.
216 10274 : IF (PRESENT(qmmm) .AND. PRESENT(qmmm_env)) my_qmmm = qmmm
217 :
218 10274 : natom = topology%natoms
219 10274 : IF (ASSOCIATED(atom_info%map_mol_typ)) DEALLOCATE (atom_info%map_mol_typ)
220 30822 : ALLOCATE (atom_info%map_mol_typ(natom))
221 :
222 10274 : IF (ASSOCIATED(atom_info%map_mol_num)) DEALLOCATE (atom_info%map_mol_num)
223 20548 : ALLOCATE (atom_info%map_mol_num(natom))
224 :
225 10274 : IF (ASSOCIATED(atom_info%map_mol_res)) DEALLOCATE (atom_info%map_mol_res)
226 20548 : ALLOCATE (atom_info%map_mol_res(natom))
227 :
228 : ! Initialisation
229 764843 : atom_info%map_mol_typ(:) = 0
230 764843 : atom_info%map_mol_num(:) = -1
231 764843 : atom_info%map_mol_res(:) = 1
232 :
233 : ! Parse the atom list to find the different molecule types and residues
234 10274 : ntype = 1
235 10274 : atom_info%map_mol_typ(1) = 1
236 10274 : resid = 1
237 10274 : CALL reallocate(wrk1, 1, nblock)
238 10274 : wrk1(1) = atom_info%id_molname(1)
239 754569 : DO iatom = 2, natom
240 754569 : IF (topology%conn_type == do_conn_off) THEN
241 : ! No connectivity: each atom becomes a molecule of its own molecule kind
242 45158 : ntype = ntype + 1
243 45158 : atom_info%map_mol_typ(iatom) = ntype
244 699137 : ELSE IF (topology%conn_type == do_conn_user) THEN
245 : ! User-defined connectivity: 5th column of COORD section or molecule
246 : ! or residue name in the case of PDB files
247 29548 : IF ((atom_info%id_molname(iatom) == atom_info%id_molname(iatom - 1)) .AND. &
248 : (.NOT. MODULO(iatom, topology%natom_muc) == 1)) THEN
249 28170 : atom_info%map_mol_typ(iatom) = atom_info%map_mol_typ(iatom - 1)
250 28170 : IF (atom_info%id_resname(iatom) == atom_info%id_resname(iatom - 1)) THEN
251 26924 : atom_info%map_mol_res(iatom) = atom_info%map_mol_res(iatom - 1)
252 : ELSE
253 1246 : resid = resid + 1
254 1246 : atom_info%map_mol_res(iatom) = resid
255 : END IF
256 : ELSE
257 : ! Check if the type is already known
258 1378 : found = .FALSE.
259 19618 : DO itype = 1, ntype
260 19618 : IF (atom_info%id_molname(iatom) == wrk1(itype)) THEN
261 998 : atom_info%map_mol_typ(iatom) = itype
262 : found = .TRUE.
263 : EXIT
264 : END IF
265 : END DO
266 : IF (.NOT. found) THEN
267 380 : ntype = ntype + 1
268 380 : atom_info%map_mol_typ(iatom) = ntype
269 380 : IF (ntype > SIZE(wrk1)) CALL reallocate(wrk1, 1, 2*SIZE(wrk1))
270 380 : wrk1(ntype) = atom_info%id_molname(iatom)
271 : END IF
272 1378 : resid = resid + 1
273 1378 : atom_info%map_mol_res(iatom) = resid
274 : END IF
275 : ELSE
276 669589 : IF (atom_info%id_molname(iatom - 1) == atom_info%id_molname(iatom)) THEN
277 592510 : atom_info%map_mol_typ(iatom) = ntype
278 : ELSE
279 77079 : ntype = ntype + 1
280 77079 : atom_info%map_mol_typ(iatom) = ntype
281 : END IF
282 : END IF
283 : END DO
284 10274 : DEALLOCATE (wrk1)
285 :
286 10274 : IF (iw > 0) WRITE (iw, '(/,T2,A)') "Start of molecule generation"
287 :
288 : ! convert a simple list of bonds to a list of bonds per atom
289 : ! (each bond is present in the forward and backward direction
290 785391 : ALLOCATE (atom_bond_list(natom))
291 764843 : DO I = 1, natom
292 764843 : ALLOCATE (atom_bond_list(I)%array1(0))
293 : END DO
294 10274 : N = 0
295 10274 : IF (ASSOCIATED(conn_info%bond_a)) N = SIZE(conn_info%bond_a)
296 10274 : CALL reorder_structure(atom_bond_list, conn_info%bond_a, conn_info%bond_b, N)
297 10274 : CALL find_molecule(atom_bond_list, atom_info%map_mol_num, atom_info%id_molname)
298 764843 : DO I = 1, natom
299 764843 : DEALLOCATE (atom_bond_list(I)%array1)
300 : END DO
301 10274 : DEALLOCATE (atom_bond_list)
302 10274 : IF (iw > 0) WRITE (iw, '(/,T2,A)') "End of molecule generation"
303 :
304 : ! Modify according map_mol_typ the array map_mol_num
305 10274 : IF (iw > 0) WRITE (iw, '(/,T2,A)') "Checking for non-continuous generated molecules"
306 : ! Check molecule number
307 20548 : ALLOCATE (wrk1(natom))
308 20548 : ALLOCATE (wrk2(natom))
309 1529686 : wrk1 = atom_info%map_mol_num
310 :
311 : IF (debug_this_module) THEN
312 : DO i = 1, natom
313 : WRITE (*, '(2I10)') i, atom_info%map_mol_num(i)
314 : END DO
315 : END IF
316 :
317 10274 : CALL sort(wrk1, natom, wrk2)
318 10274 : istart = 1
319 10274 : mol_typ = wrk1(istart)
320 754569 : DO i = 2, natom
321 754569 : IF (mol_typ /= wrk1(i)) THEN
322 319090 : iend = i - 1
323 1046163 : first = MINVAL(wrk2(istart:iend))
324 1046163 : last = MAXVAL(wrk2(istart:iend))
325 319090 : nlocl = last - first + 1
326 319090 : IF (iend - istart + 1 /= nlocl) THEN
327 : IF (debug_this_module) WRITE (*, *) iend, istart, iend - istart + 1, first, last, nlocl
328 : CALL cp_abort(__LOCATION__, &
329 : "CP2K requires molecules to be contiguous and we have detected a non contiguous one!! "// &
330 : "In particular a molecule defined from index ("//cp_to_string(first)//") to ("// &
331 : cp_to_string(last)//") contains other molecules, not connected! "// &
332 : "Too late at this stage everything should be already ordered! "// &
333 : "If you have not yet employed the REORDERING keyword, please do so. "// &
334 0 : "It may help to fix this issue.")
335 : END IF
336 319090 : istart = i
337 319090 : mol_typ = wrk1(istart)
338 : END IF
339 : END DO
340 10274 : iend = i - 1
341 37770 : first = MINVAL(wrk2(istart:iend))
342 37770 : last = MAXVAL(wrk2(istart:iend))
343 10274 : nlocl = last - first + 1
344 10274 : IF (iend - istart + 1 /= nlocl) THEN
345 : IF (debug_this_module) WRITE (*, *) iend, istart, iend - istart + 1, first, last, nlocl
346 : CALL cp_abort(__LOCATION__, &
347 : "CP2K requires molecules to be contiguous and we have detected a non contiguous one!! "// &
348 : "In particular a molecule defined from index ("//cp_to_string(first)//") to ("// &
349 : cp_to_string(last)//") contains other molecules, not connected! "// &
350 : "Too late at this stage everything should be already ordered! "// &
351 : "If you have not yet employed the REORDERING keyword, please do so. "// &
352 0 : "It may help to fix this issue.")
353 : END IF
354 10274 : DEALLOCATE (wrk1)
355 10274 : DEALLOCATE (wrk2)
356 10274 : IF (iw > 0) WRITE (iw, '(/,T2,A)') "End of check"
357 :
358 10274 : IF (iw > 0) WRITE (UNIT=iw, FMT="(/,T2,A)") "Start of renumbering molecules"
359 10274 : IF (topology%conn_type == do_conn_user) THEN
360 164 : mol_num = 1
361 164 : atom_info%map_mol_num(1) = 1
362 29712 : DO iatom = 2, natom
363 29548 : IF (atom_info%id_molname(iatom) /= atom_info%id_molname(iatom - 1)) THEN
364 : mol_num = 1
365 29168 : ELSE IF (atom_info%map_mol_res(iatom) /= atom_info%map_mol_res(iatom - 1)) THEN
366 2244 : mol_num = mol_num + 1
367 : END IF
368 29712 : atom_info%map_mol_num(iatom) = mol_num
369 : END DO
370 : ELSE
371 10110 : mol_typ = atom_info%map_mol_typ(1)
372 10110 : mol_num = atom_info%map_mol_num(1)
373 724857 : DO i = 2, natom
374 714747 : IF (atom_info%map_mol_typ(i) /= mol_typ) THEN
375 122237 : myind = atom_info%map_mol_num(i) - mol_num + 1
376 122237 : CPASSERT(myind /= atom_info%map_mol_num(i - 1))
377 122237 : mol_typ = atom_info%map_mol_typ(i)
378 122237 : mol_num = atom_info%map_mol_num(i)
379 : END IF
380 724857 : atom_info%map_mol_num(i) = atom_info%map_mol_num(i) - mol_num + 1
381 : END DO
382 : END IF
383 10274 : IF (iw > 0) WRITE (UNIT=iw, FMT="(/,T2,A)") "End of renumbering molecules"
384 :
385 : ! Optionally, use the residues as molecules
386 10274 : CALL timeset(routineN//"_PARA_RES", handle2)
387 10274 : IF (iw > 0) WRITE (UNIT=iw, FMT="(/,T2,A,L2)") "Starting PARA_RES: ", topology%para_res
388 10274 : IF (topology%para_res) THEN
389 9560 : IF (topology%conn_type == do_conn_user) THEN
390 0 : atom_info%id_molname(:) = atom_info%id_resname(:)
391 0 : ntype = 1
392 0 : atom_info%map_mol_typ(1) = 1
393 0 : mol_num = 1
394 0 : atom_info%map_mol_num(1) = 1
395 0 : DO iatom = 2, natom
396 0 : IF (atom_info%id_molname(iatom) /= atom_info%id_molname(iatom - 1)) THEN
397 0 : ntype = ntype + 1
398 0 : mol_num = 1
399 0 : ELSE IF (atom_info%map_mol_res(iatom) /= atom_info%map_mol_res(iatom - 1)) THEN
400 0 : mol_num = mol_num + 1
401 : END IF
402 0 : atom_info%map_mol_typ(iatom) = ntype
403 0 : atom_info%map_mol_num(iatom) = mol_num
404 : END DO
405 : ELSE
406 9560 : mol_res = 1
407 9560 : mol_typ = atom_info%map_mol_typ(1)
408 9560 : mol_num = atom_info%map_mol_num(1)
409 9560 : atom_info%map_mol_res(1) = mol_res
410 720961 : DO i = 2, natom
411 711401 : IF ((atom_info%resid(i - 1) /= atom_info%resid(i)) .OR. &
412 : (atom_info%id_resname(i - 1) /= atom_info%id_resname(i))) THEN
413 216863 : mol_res = mol_res + 1
414 : END IF
415 711401 : IF ((atom_info%map_mol_typ(i) /= mol_typ) .OR. &
416 : (atom_info%map_mol_num(i) /= mol_num)) THEN
417 286324 : mol_typ = atom_info%map_mol_typ(i)
418 286324 : mol_num = atom_info%map_mol_num(i)
419 286324 : mol_res = 1
420 : END IF
421 720961 : atom_info%map_mol_res(i) = mol_res
422 : END DO
423 : END IF
424 : END IF
425 10274 : IF (iw > 0) WRITE (UNIT=iw, FMT="(/,T2,A)") "End of PARA_RES"
426 10274 : CALL timestop(handle2)
427 :
428 10274 : IF (iw > 0) THEN
429 1557 : DO iatom = 1, natom
430 1531 : WRITE (iw, '(4(1X,A,":",I0),2(1X,A,1X,A))') "iatom", iatom, &
431 1531 : "map_mol_typ", atom_info%map_mol_typ(iatom), &
432 1531 : "map_mol_num", atom_info%map_mol_num(iatom), &
433 1531 : "map_mol_res", atom_info%map_mol_res(iatom), &
434 1531 : "mol_name:", TRIM(id2str(atom_info%id_molname(iatom))), &
435 3088 : "res_name:", TRIM(id2str(atom_info%id_resname(iatom)))
436 : END DO
437 : END IF
438 :
439 10274 : IF (my_qmmm) THEN
440 394 : do_again = .FALSE.
441 394 : IF (iw > 0) WRITE (iw, *) "MAP_MOL_NUM ", atom_info%map_mol_num
442 394 : IF (iw > 0) WRITE (iw, *) "MAP_MOL_TYP ", atom_info%map_mol_typ
443 394 : IF (iw > 0) WRITE (iw, *) "MAP_MOL_RES ", atom_info%map_mol_res
444 1182 : ALLOCATE (qm_atom_index(SIZE(qmmm_env%qm_atom_index)))
445 6572 : qm_atom_index = qmmm_env%qm_atom_index
446 3286 : CPASSERT(ALL(qm_atom_index /= 0))
447 1958 : DO myind = 1, SIZE(qm_atom_index)
448 1854 : IF (qm_atom_index(myind) == 0) CYCLE
449 : CALL find_boundary(atom_info%map_mol_typ, natom, ifirst, ilast, &
450 974 : atom_info%map_mol_typ(qm_atom_index(myind)))
451 : CALL find_boundary(atom_info%map_mol_typ, atom_info%map_mol_num, natom, ifirst, ilast, &
452 974 : atom_info%map_mol_typ(qm_atom_index(myind)), atom_info%map_mol_num(qm_atom_index(myind)))
453 974 : IF (iw > 0) WRITE (iw, *) "qm fragment:: ifirst, ilast", ifirst, ilast
454 974 : CPASSERT(((ifirst /= 0) .OR. (ilast /= natom)))
455 16314 : DO iatm = ifirst, ilast
456 : atom_info%id_molname(iatm) = str2id(s2s("_QM_"// &
457 15340 : TRIM(id2str(atom_info%id_molname(iatm)))))
458 15340 : IF (iw > 0) WRITE (iw, *) "QM Molecule name :: ", id2str(atom_info%id_molname(iatm))
459 786952 : WHERE (qm_atom_index == iatm) qm_atom_index = 0
460 : END DO
461 466890 : DO iatm = 1, ifirst - 1
462 59902382 : IF (ANY(qm_atom_index == iatm)) do_again = .TRUE.
463 : END DO
464 626780 : DO iatm = ilast + 1, natom
465 62275092 : IF (ANY(qm_atom_index == iatm)) do_again = .TRUE.
466 : END DO
467 974 : IF (iw > 0) WRITE (iw, *) " Another QM fragment? :: ", do_again
468 974 : IF (ifirst /= 1) THEN
469 656 : jump1 = atom_info%map_mol_typ(ifirst) - atom_info%map_mol_typ(ifirst - 1)
470 656 : CPASSERT(jump1 <= 1 .AND. jump1 >= 0)
471 656 : jump1 = ABS(jump1 - 1)
472 : ELSE
473 : jump1 = 0
474 : END IF
475 974 : IF (ilast /= natom) THEN
476 878 : jump2 = atom_info%map_mol_typ(ilast + 1) - atom_info%map_mol_typ(ilast)
477 878 : CPASSERT(jump2 <= 1 .AND. jump2 >= 0)
478 878 : jump2 = ABS(jump2 - 1)
479 : ELSE
480 : jump2 = 0
481 : END IF
482 :
483 : ! Changing mol_type consistently
484 642120 : DO iatm = ifirst, natom
485 642120 : atom_info%map_mol_typ(iatm) = atom_info%map_mol_typ(iatm) + jump1
486 : END DO
487 626780 : DO iatm = ilast + 1, natom
488 626780 : atom_info%map_mol_typ(iatm) = atom_info%map_mol_typ(iatm) + jump2
489 : END DO
490 974 : IF (jump1 == 1) THEN
491 608 : DO iatm = ifirst, ilast
492 608 : atom_info%map_mol_num(iatm) = 1
493 : END DO
494 : END IF
495 :
496 974 : IF (jump2 == 1) THEN
497 254 : CALL find_boundary(atom_info%map_mol_typ, natom, first, last, atom_info%map_mol_typ(ilast + 1))
498 : CALL find_boundary(atom_info%map_mol_typ, atom_info%map_mol_num, natom, ifirst, ilast, &
499 254 : atom_info%map_mol_typ(ilast + 1), atom_info%map_mol_num(ilast + 1))
500 254 : atom_in_mol = ilast - ifirst + 1
501 254 : inum = 1
502 254 : DO iatm = first, last, atom_in_mol
503 167580 : atom_info%map_mol_num(iatm:iatm + atom_in_mol - 1) = inum
504 42224 : inum = inum + 1
505 : END DO
506 : END IF
507 :
508 2052 : IF (.NOT. do_again) EXIT
509 : END DO
510 394 : DEALLOCATE (qm_atom_index)
511 :
512 394 : IF (iw > 0) THEN
513 0 : WRITE (iw, *) "After the QM/MM Setup:"
514 0 : DO iatom = 1, natom
515 0 : WRITE (iw, *) " iatom,map_mol_typ,map_mol_num ", iatom, &
516 0 : atom_info%map_mol_typ(iatom), atom_info%map_mol_num(iatom)
517 : END DO
518 : END IF
519 : END IF
520 : !
521 : ! Further check : see if the number of atoms belonging to same molecule kinds
522 : ! are equal
523 10274 : IF (iw > 0) THEN
524 26 : WRITE (iw, *) "SUMMARY:: Number of molecule kinds found:", ntype
525 1557 : ntype = MAXVAL(atom_info%map_mol_typ)
526 458 : DO i = 1, ntype
527 154987 : atom_in_kind = COUNT(atom_info%map_mol_typ == i)
528 432 : WRITE (iw, *) "Molecule kind:", i, " contains", atom_in_kind, " atoms"
529 432 : IF (atom_in_kind <= 1) CYCLE
530 24 : CALL find_boundary(atom_info%map_mol_typ, natom, first, last, i)
531 24 : WRITE (iw, *) "Boundary atoms:", first, last
532 24 : CPASSERT(last - first + 1 == atom_in_kind)
533 1147 : max_mol_num = MAXVAL(atom_info%map_mol_num(first:last))
534 24 : WRITE (iw, *) "Number of molecules of kind", i, "is ::", max_mol_num
535 24 : atom_in_mol = atom_in_kind/max_mol_num
536 24 : WRITE (iw, *) "Number of atoms per each molecule:", atom_in_mol
537 24 : WRITE (iw, *) "MAP_MOL_TYP::", atom_info%map_mol_typ(first:last)
538 24 : WRITE (iw, *) "MAP_MOL_NUM::", atom_info%map_mol_num(first:last)
539 24 : WRITE (iw, *) "MAP_MOL_RES::", atom_info%map_mol_res(first:last)
540 : !
541 194 : DO j = 1, max_mol_num
542 31705 : IF (COUNT(atom_info%map_mol_num(first:last) == j) /= atom_in_mol) THEN
543 0 : WRITE (iw, *) "molecule type:", i, "molecule num:", j, " has ", &
544 0 : COUNT(atom_info%map_mol_num(first:last) == j), &
545 0 : " atoms instead of ", atom_in_mol, " ."
546 : CALL cp_abort(__LOCATION__, &
547 : "Two molecules of the same kind have "// &
548 0 : "been created with different numbers of atoms!")
549 : END IF
550 : END DO
551 : END DO
552 : END IF
553 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
554 10274 : "PRINT%TOPOLOGY_INFO/UTIL_INFO")
555 10274 : CALL timestop(handle)
556 41096 : END SUBROUTINE topology_generate_molecule
557 :
558 : ! **************************************************************************************************
559 : !> \brief Use info from periodic table and assumptions to generate bonds
560 : !> \param topology ...
561 : !> \param para_env ...
562 : !> \param subsys_section ...
563 : !> \author Teodoro Laino 09.2006
564 : ! **************************************************************************************************
565 8143 : SUBROUTINE topology_generate_bond(topology, para_env, subsys_section)
566 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
567 : TYPE(mp_para_env_type), POINTER :: para_env
568 : TYPE(section_vals_type), POINTER :: subsys_section
569 :
570 : CHARACTER(len=*), PARAMETER :: routineN = 'topology_generate_bond'
571 :
572 : CHARACTER(LEN=2) :: upper_sym_1
573 : INTEGER :: cbond, handle, handle2, i, iatm1, iatm2, iatom, ibond, idim, iw, j, jatom, k, &
574 : n_bonds, n_heavy_bonds, n_hydr_bonds, n_rep, natom, npairs, output_unit
575 8143 : INTEGER, ALLOCATABLE, DIMENSION(:) :: bond_a, bond_b, list, map_nb
576 8143 : INTEGER, DIMENSION(:), POINTER :: isolated_atoms, tmp_v
577 : LOGICAL :: connectivity_ok, explicit, print_info
578 8143 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: h_list
579 : REAL(KIND=dp) :: bondparm_factor, cell_v(3), dr(3), &
580 : ksign, my_maxrad, r2, r2_min, rbond, &
581 : rbond2, tmp
582 : REAL(KIND=dp), DIMENSION(1, 1) :: r_max, r_minsq
583 8143 : REAL(KIND=dp), DIMENSION(:), POINTER :: radius
584 8143 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: pbc_coord
585 8143 : TYPE(array2_list_type), DIMENSION(:), POINTER :: bond_list
586 : TYPE(atom_info_type), POINTER :: atom_info
587 8143 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
588 : TYPE(atomic_kind_type), POINTER :: atomic_kind
589 : TYPE(connectivity_info_type), POINTER :: conn_info
590 : TYPE(cp_logger_type), POINTER :: logger
591 : TYPE(fist_neighbor_type), POINTER :: nonbonded
592 8143 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
593 : TYPE(section_vals_type), POINTER :: bond_section, generate_section, &
594 : isolated_section
595 :
596 8143 : NULLIFY (logger, particle_set, atomic_kind_set, nonbonded, bond_section, generate_section)
597 8143 : NULLIFY (isolated_atoms, tmp_v)
598 8143 : CALL timeset(routineN, handle)
599 8143 : logger => cp_get_default_logger()
600 8143 : output_unit = cp_logger_get_default_io_unit(logger)
601 : iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/GENERATE_INFO", &
602 8143 : extension=".subsysLog")
603 : ! Get atoms that one considers isolated (like ions in solution)
604 8143 : ALLOCATE (isolated_atoms(0))
605 8143 : generate_section => section_vals_get_subs_vals(subsys_section, "TOPOLOGY%GENERATE")
606 8143 : isolated_section => section_vals_get_subs_vals(generate_section, "ISOLATED_ATOMS")
607 8143 : CALL section_vals_get(isolated_section, explicit=explicit)
608 8143 : IF (explicit) THEN
609 8 : CALL section_vals_val_get(isolated_section, "LIST", n_rep_val=n_rep)
610 20 : DO i = 1, n_rep
611 12 : CALL section_vals_val_get(isolated_section, "LIST", i_vals=tmp_v, i_rep_val=i)
612 12 : CALL reallocate(isolated_atoms, 1, SIZE(isolated_atoms) + SIZE(tmp_v))
613 196 : isolated_atoms(SIZE(isolated_atoms) - SIZE(tmp_v) + 1:SIZE(isolated_atoms)) = tmp_v
614 : END DO
615 : END IF
616 8143 : atom_info => topology%atom_info
617 8143 : conn_info => topology%conn_info
618 8143 : bondparm_factor = topology%bondparm_factor
619 8143 : cbond = 0
620 8143 : natom = topology%natoms
621 8143 : NULLIFY (radius)
622 : ! Allocate temporary arrays
623 24429 : ALLOCATE (radius(natom))
624 24429 : ALLOCATE (list(natom))
625 16286 : ALLOCATE (h_list(natom))
626 24429 : ALLOCATE (pbc_coord(3, natom))
627 224563 : h_list = .FALSE.
628 8143 : CALL timeset(TRIM(routineN)//"_1", handle2)
629 224563 : DO iatom = 1, natom
630 216420 : list(iatom) = iatom
631 216420 : upper_sym_1 = TRIM(id2str(atom_info%id_element(iatom)))
632 216420 : IF (topology%bondparm_type == do_bondparm_covalent) THEN
633 216420 : CALL get_ptable_info(symbol=upper_sym_1, covalent_radius=radius(iatom))
634 0 : ELSE IF (topology%bondparm_type == do_bondparm_vdw) THEN
635 0 : CALL get_ptable_info(symbol=upper_sym_1, vdw_radius=radius(iatom))
636 : ELSE
637 0 : CPABORT("Illegal bondparm_type")
638 : END IF
639 216420 : IF (upper_sym_1 == "H ") h_list(iatom) = .TRUE.
640 : ! isolated atoms? put the radius to 0.0_dp
641 342296 : IF (ANY(isolated_atoms == iatom)) radius(iatom) = 0.0_dp
642 216420 : radius(iatom) = cp_unit_to_cp2k(radius(iatom), "angstrom")
643 216420 : IF (iw > 0) WRITE (iw, '(T2,"GENERATE|",5X,A,T50,A5,T60,A,T69,F12.6)') &
644 3186 : "In topology_generate_bond :: iatom = ", upper_sym_1, &
645 14515 : "radius:", radius(iatom)
646 : END DO
647 8143 : CALL timestop(handle2)
648 8143 : CALL timeset(TRIM(routineN)//"_2", handle2)
649 : ! Initialize fake particle_set and atomic_kinds to generate the bond list
650 : ! using the neighboring list routine
651 16286 : ALLOCATE (atomic_kind_set(1))
652 8143 : CALL allocate_particle_set(particle_set, natom)
653 : !
654 232706 : my_maxrad = MAXVAL(radius)*2.0_dp
655 8143 : atomic_kind => atomic_kind_set(1)
656 : CALL set_atomic_kind(atomic_kind=atomic_kind, kind_number=1, &
657 8143 : name="XXX", element_symbol="XXX", mass=0.0_dp, atom_list=list)
658 8143 : CALL section_vals_val_get(subsys_section, "TOPOLOGY%GENERATE%BONDLENGTH_MAX", r_val=tmp)
659 24429 : r_max = tmp
660 8143 : IF (my_maxrad*bondparm_factor > r_max(1, 1) .AND. (.NOT. topology%molname_generated)) THEN
661 0 : IF (output_unit > 0) THEN
662 : WRITE (output_unit, '(T2,"GENERATE|",A)') &
663 0 : " ERROR in connectivity generation!", &
664 0 : " The THRESHOLD to select possible bonds is larger than the max. bondlength", &
665 0 : " used to build the neighbors lists. Increase the BONDLENGTH_MAX parameter"
666 : WRITE (output_unit, '(T2,"GENERATE|",2(A,F11.6),A)') &
667 0 : " Present THRESHOLD (", my_maxrad*bondparm_factor, " )."// &
668 0 : " Present BONDLENGTH_MAX (", r_max(1, 1), " )"
669 : END IF
670 0 : CPABORT("")
671 : END IF
672 224563 : DO i = 1, natom
673 216420 : particle_set(i)%atomic_kind => atomic_kind_set(1)
674 216420 : particle_set(i)%r(1) = atom_info%r(1, i)
675 216420 : particle_set(i)%r(2) = atom_info%r(2, i)
676 216420 : particle_set(i)%r(3) = atom_info%r(3, i)
677 873823 : pbc_coord(:, i) = pbc(atom_info%r(:, i), topology%cell)
678 : END DO
679 8143 : CALL section_vals_val_get(subsys_section, "TOPOLOGY%GENERATE%BONDLENGTH_MIN", r_val=tmp)
680 24429 : r_minsq = tmp*tmp
681 8143 : CALL timestop(handle2)
682 8143 : CALL timeset(TRIM(routineN)//"_3", handle2)
683 : CALL build_fist_neighbor_lists(atomic_kind_set, particle_set, &
684 : cell=topology%cell, r_max=r_max, r_minsq=r_minsq, &
685 : ei_scale14=1.0_dp, vdw_scale14=1.0_dp, nonbonded=nonbonded, &
686 : para_env=para_env, build_from_scratch=.TRUE., geo_check=.TRUE., &
687 8143 : mm_section=generate_section)
688 8143 : IF (iw > 0) THEN
689 : WRITE (iw, '(T2,"GENERATE| Number of prescreened bonds (neighbors):",T71,I10)') &
690 8 : nonbonded%neighbor_kind_pairs(1)%npairs
691 : END IF
692 8143 : npairs = 0
693 148304 : DO i = 1, SIZE(nonbonded%neighbor_kind_pairs)
694 148304 : npairs = npairs + nonbonded%neighbor_kind_pairs(i)%npairs
695 : END DO
696 23681 : ALLOCATE (bond_a(npairs))
697 15538 : ALLOCATE (bond_b(npairs))
698 15538 : ALLOCATE (map_nb(npairs))
699 8143 : idim = 0
700 148304 : DO j = 1, SIZE(nonbonded%neighbor_kind_pairs)
701 1288005 : DO i = 1, nonbonded%neighbor_kind_pairs(j)%npairs
702 1139701 : idim = idim + 1
703 1139701 : bond_a(idim) = nonbonded%neighbor_kind_pairs(j)%list(1, i)
704 1139701 : bond_b(idim) = nonbonded%neighbor_kind_pairs(j)%list(2, i)
705 1279862 : map_nb(idim) = j
706 : END DO
707 : END DO
708 8143 : CALL timestop(handle2)
709 8143 : CALL timeset(TRIM(routineN)//"_4", handle2)
710 : ! We have a list of neighbors let's order the list w.r.t. the particle number
711 240849 : ALLOCATE (bond_list(natom))
712 224563 : DO I = 1, natom
713 216420 : ALLOCATE (bond_list(I)%array1(0))
714 224563 : ALLOCATE (bond_list(I)%array2(0))
715 : END DO
716 8143 : CALL reorder_structure(bond_list, bond_a, bond_b, map_nb, SIZE(bond_a))
717 8143 : DEALLOCATE (bond_a)
718 8143 : DEALLOCATE (bond_b)
719 8143 : DEALLOCATE (map_nb)
720 : ! Find the Real bonds in the system
721 : ! Let's start with heavy atoms.. hydrogens will be treated only later on...
722 : ! Heavy atoms loop
723 8143 : CALL reallocate(conn_info%bond_a, 1, 1)
724 8143 : CALL reallocate(conn_info%bond_b, 1, 1)
725 8143 : connectivity_ok = .FALSE.
726 : ! No need to check consistency between provided molecule name and
727 : ! generated connectivity since we overrided the molecule definition.
728 8143 : IF (topology%create_molecules) THEN
729 8858 : atom_info%id_molname = str2id(s2s("TO_DEFINE_LATER"))
730 : ! A real name assignment will then be performed in the reorder module..
731 : END IF
732 : ! It may happen that the connectivity created is fault for the missing
733 : ! of one bond.. this external loop ensures that everything was created
734 : ! fits exactly with the definition of molecules..
735 16288 : DO WHILE (.NOT. connectivity_ok)
736 8145 : n_heavy_bonds = 0
737 8145 : n_bonds = 0
738 225795 : DO iatm1 = 1, natom
739 217650 : IF (h_list(iatm1)) CYCLE
740 1115203 : DO j = 1, SIZE(bond_list(iatm1)%array1)
741 1001932 : iatm2 = bond_list(iatm1)%array1(j)
742 1001932 : IF (atom_info%id_molname(iatm1) /= atom_info%id_molname(iatm2)) CYCLE
743 674796 : IF (h_list(iatm2) .OR. (iatm2 <= iatm1)) CYCLE
744 135976 : k = bond_list(iatm1)%array2(j)
745 135976 : ksign = SIGN(1.0_dp, REAL(k, KIND=dp))
746 135976 : k = ABS(k)
747 : cell_v = MATMUL(topology%cell%hmat, &
748 2175616 : REAL(nonbonded%neighbor_kind_pairs(k)%cell_vector, KIND=dp))
749 543904 : dr = pbc_coord(:, iatm1) - pbc_coord(:, iatm2) - ksign*cell_v
750 543904 : r2 = DOT_PRODUCT(dr, dr)
751 135976 : IF (r2 <= r_minsq(1, 1)) THEN
752 : CALL cp_abort(__LOCATION__, &
753 : "bond distance between atoms less then the smallest distance provided "// &
754 0 : "in input "//cp_to_string(tmp)//" [bohr]")
755 : END IF
756 : ! Screen isolated atoms
757 1609678 : IF ((ANY(isolated_atoms == iatm1)) .OR. (ANY(isolated_atoms == iatm2))) CYCLE
758 :
759 : ! Screen neighbors
760 134512 : IF (topology%bondparm_type == do_bondparm_covalent) THEN
761 134512 : rbond = radius(iatm1) + radius(iatm2)
762 0 : ELSE IF (topology%bondparm_type == do_bondparm_vdw) THEN
763 0 : rbond = MAX(radius(iatm1), radius(iatm2))
764 : END IF
765 134512 : rbond2 = rbond*rbond
766 134512 : rbond2 = rbond2*(bondparm_factor)**2
767 : !Test the distance to the sum of the covalent radius
768 352162 : IF (r2 <= rbond2) THEN
769 16472 : n_heavy_bonds = n_heavy_bonds + 1
770 16472 : CALL add_bonds_list(conn_info, iatm1, iatm2, n_heavy_bonds)
771 : END IF
772 : END DO
773 : END DO
774 8145 : n_hydr_bonds = 0
775 8145 : n_bonds = n_heavy_bonds
776 : ! Now check bonds formed by hydrogens...
777 : ! The hydrogen valence is 1 so we can choose the closest atom..
778 8145 : IF (output_unit > 0) WRITE (output_unit, *)
779 225795 : DO iatm1 = 1, natom
780 217650 : IF (.NOT. h_list(iatm1)) CYCLE
781 112524 : r2_min = HUGE(0.0_dp)
782 112524 : ibond = -1
783 112524 : print_info = .TRUE.
784 1396558 : DO j = 1, SIZE(bond_list(iatm1)%array1)
785 1284034 : iatm2 = bond_list(iatm1)%array1(j)
786 1284034 : print_info = .FALSE.
787 1284034 : IF (atom_info%id_molname(iatm1) /= atom_info%id_molname(iatm2)) CYCLE
788 1202244 : IF (h_list(iatm2) .AND. (iatm2 <= iatm1)) CYCLE
789 : ! Screen isolated atoms
790 12227886 : IF ((ANY(isolated_atoms == iatm1)) .OR. (ANY(isolated_atoms == iatm2))) CYCLE
791 :
792 799216 : k = bond_list(iatm1)%array2(j)
793 799216 : ksign = SIGN(1.0_dp, REAL(k, KIND=dp))
794 799216 : k = ABS(k)
795 : cell_v = MATMUL(topology%cell%hmat, &
796 12787456 : REAL(nonbonded%neighbor_kind_pairs(k)%cell_vector, KIND=dp))
797 3196864 : dr = pbc_coord(:, iatm1) - pbc_coord(:, iatm2) - ksign*cell_v
798 3196864 : r2 = DOT_PRODUCT(dr, dr)
799 799216 : IF (r2 <= r_minsq(1, 1)) THEN
800 : CALL cp_abort(__LOCATION__, &
801 : "bond distance between atoms less then the smallest distance provided "// &
802 0 : "in input "//cp_to_string(tmp)//" [bohr]")
803 : END IF
804 911740 : IF (r2 <= r2_min) THEN
805 227224 : r2_min = r2
806 227224 : ibond = iatm2
807 : END IF
808 : END DO
809 120669 : IF (ibond == -1) THEN
810 13678 : IF (output_unit > 0 .AND. print_info) THEN
811 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,I10,A)') &
812 133 : "WARNING:: No connections detected for Hydrogen - Atom Nr:", iatm1, " !"
813 : END IF
814 : ELSE
815 98846 : n_hydr_bonds = n_hydr_bonds + 1
816 98846 : n_bonds = n_bonds + 1
817 98846 : CALL add_bonds_list(conn_info, MIN(iatm1, ibond), MAX(iatm1, ibond), n_bonds)
818 : END IF
819 : END DO
820 8145 : IF (output_unit > 0) THEN
821 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') &
822 4172 : " Preliminary Number of Bonds generated:", n_bonds
823 : END IF
824 : ! External defined bonds (useful for complex connectivity)
825 8145 : bond_section => section_vals_get_subs_vals(generate_section, "BOND")
826 : CALL connectivity_external_control(section=bond_section, &
827 : Iarray1=conn_info%bond_a, &
828 : Iarray2=conn_info%bond_b, &
829 : nvar=n_bonds, &
830 : topology=topology, &
831 8145 : output_unit=output_unit)
832 : ! Resize arrays to their proper size..
833 8145 : CALL reallocate(conn_info%bond_a, 1, n_bonds)
834 8145 : CALL reallocate(conn_info%bond_b, 1, n_bonds)
835 8145 : IF (topology%create_molecules) THEN
836 : ! Since we create molecule names we're not sure that all atoms are contiguous
837 : ! so we need to reorder them on the basis of the generated name
838 312 : IF (.NOT. topology%reorder_atom) THEN
839 302 : topology%reorder_atom = .TRUE.
840 302 : IF (output_unit > 0) WRITE (output_unit, '(T2,"GENERATE|",A)') &
841 151 : " Molecules names have been generated. Now reordering particle set in order to have ", &
842 302 : " atoms belonging to the same molecule in a sequential order."
843 : END IF
844 : connectivity_ok = .TRUE.
845 : ELSE
846 : ! Check created connectivity and possibly give the OK to proceed
847 : connectivity_ok = check_generate_mol(conn_info%bond_a, conn_info%bond_b, &
848 7833 : atom_info, bondparm_factor, output_unit)
849 : END IF
850 16288 : IF (my_maxrad*bondparm_factor > r_max(1, 1) .AND. (.NOT. topology%molname_generated)) THEN
851 0 : IF (output_unit > 0) THEN
852 : WRITE (output_unit, '(T2,"GENERATE|",A)') &
853 0 : " ERROR in connectivity generation!", &
854 0 : " The THRESHOLD to select possible bonds is bigger than the MAX bondlength", &
855 0 : " used to build the neighbors lists. Increase the BONDLENGTH_MAX patameter"
856 : WRITE (output_unit, '(T2,"GENERATE|",2(A,F11.6),A)') &
857 0 : " Present THRESHOLD (", my_maxrad*bondparm_factor, " )."// &
858 0 : " Present BONDLENGTH_MAX (", r_max(1, 1), " )"
859 : END IF
860 0 : CPABORT("")
861 : END IF
862 : END DO
863 8143 : IF (connectivity_ok .AND. (output_unit > 0)) THEN
864 : WRITE (output_unit, '(T2,"GENERATE|",A)') &
865 4171 : " Achieved consistency in connectivity generation."
866 : END IF
867 8143 : CALL fist_neighbor_deallocate(nonbonded)
868 8143 : CALL timestop(handle2)
869 8143 : CALL timeset(TRIM(routineN)//"_6", handle2)
870 : ! Deallocate temporary working arrays
871 224563 : DO I = 1, natom
872 216420 : DEALLOCATE (bond_list(I)%array1)
873 224563 : DEALLOCATE (bond_list(I)%array2)
874 : END DO
875 8143 : DEALLOCATE (bond_list)
876 8143 : DEALLOCATE (pbc_coord)
877 8143 : DEALLOCATE (radius)
878 8143 : DEALLOCATE (list)
879 8143 : CALL deallocate_particle_set(particle_set)
880 8143 : CALL deallocate_atomic_kind_set(atomic_kind_set)
881 : !
882 8143 : CALL timestop(handle2)
883 8143 : IF (output_unit > 0 .AND. n_bonds > 0) THEN
884 1142 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Number of Bonds generated:", &
885 2284 : n_bonds
886 : END IF
887 8143 : CALL timeset(TRIM(routineN)//"_7", handle2)
888 : ! If PARA_RES then activate RESIDUES
889 8143 : CALL reallocate(conn_info%c_bond_a, 1, 0)
890 8143 : CALL reallocate(conn_info%c_bond_b, 1, 0)
891 8143 : IF (topology%para_res) THEN
892 122427 : DO ibond = 1, SIZE(conn_info%bond_a)
893 114284 : iatom = conn_info%bond_a(ibond)
894 114284 : jatom = conn_info%bond_b(ibond)
895 : IF ((atom_info%id_molname(iatom) /= atom_info%id_molname(jatom)) .OR. &
896 114284 : (atom_info%resid(iatom) /= atom_info%resid(jatom)) .OR. &
897 8143 : (atom_info%id_resname(iatom) /= atom_info%id_resname(jatom))) THEN
898 6446 : IF (iw > 0) WRITE (iw, *) " PARA_RES, bond between molecules atom ", &
899 4 : iatom, jatom
900 6444 : cbond = cbond + 1
901 6444 : CALL reallocate(conn_info%c_bond_a, 1, cbond)
902 6444 : CALL reallocate(conn_info%c_bond_b, 1, cbond)
903 6444 : conn_info%c_bond_a(cbond) = iatom
904 6444 : conn_info%c_bond_b(cbond) = jatom
905 : ELSE
906 : IF (atom_info%id_molname(iatom) /= atom_info%id_molname(jatom)) THEN
907 : CPABORT("Bonds between different molecule types?")
908 : END IF
909 : END IF
910 : END DO
911 : END IF
912 8143 : CALL timestop(handle2)
913 8143 : DEALLOCATE (isolated_atoms)
914 8143 : CALL timestop(handle)
915 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
916 8143 : "PRINT%TOPOLOGY_INFO/GENERATE_INFO")
917 89573 : END SUBROUTINE topology_generate_bond
918 :
919 : ! **************************************************************************************************
920 : !> \brief Performs a check on the generated connectivity
921 : !> \param bond_a ...
922 : !> \param bond_b ...
923 : !> \param atom_info ...
924 : !> \param bondparm_factor ...
925 : !> \param output_unit ...
926 : !> \return ...
927 : !> \author Teodoro Laino 09.2006
928 : ! **************************************************************************************************
929 7833 : FUNCTION check_generate_mol(bond_a, bond_b, atom_info, bondparm_factor, output_unit) &
930 : RESULT(conn_ok)
931 : INTEGER, DIMENSION(:), POINTER :: bond_a, bond_b
932 : TYPE(atom_info_type), POINTER :: atom_info
933 : REAL(KIND=dp), INTENT(INOUT) :: bondparm_factor
934 : INTEGER, INTENT(IN) :: output_unit
935 : LOGICAL :: conn_ok
936 :
937 : CHARACTER(len=*), PARAMETER :: routineN = 'check_generate_mol'
938 :
939 : CHARACTER(LEN=10) :: ctmp1, ctmp2, ctmp3
940 : INTEGER :: handle, i, idim, itype, j, mol_natom, &
941 : natom, nsize
942 7833 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: mol_info_tmp
943 7833 : INTEGER, DIMENSION(:), POINTER :: mol_map, mol_map_o, wrk
944 7833 : INTEGER, DIMENSION(:, :), POINTER :: mol_info
945 7833 : LOGICAL, DIMENSION(:), POINTER :: icheck
946 7833 : TYPE(array1_list_type), DIMENSION(:), POINTER :: bond_list
947 :
948 7833 : CALL timeset(routineN, handle)
949 7833 : conn_ok = .TRUE.
950 7833 : natom = SIZE(atom_info%id_atmname)
951 232603 : ALLOCATE (bond_list(natom))
952 216937 : DO I = 1, natom
953 216937 : ALLOCATE (bond_list(I)%array1(0))
954 : END DO
955 7833 : CALL reorder_structure(bond_list, bond_a, bond_b, SIZE(bond_a))
956 23499 : ALLOCATE (mol_map(natom))
957 15666 : ALLOCATE (mol_map_o(natom))
958 15666 : ALLOCATE (wrk(natom))
959 :
960 216937 : DO i = 1, natom
961 216937 : mol_map(i) = atom_info%id_molname(i)
962 : END DO
963 426041 : mol_map_o = mol_map
964 :
965 7833 : CALL sort(mol_map, natom, wrk)
966 : !
967 : ! mol(i,1) : stores id of the molecule
968 : ! mol(i,2) : stores the total number of atoms forming that kind of molecule
969 : ! mol(i,3) : contains the number of molecules generated for that kind
970 : ! mol(i,4) : contains the number of atoms forming one molecule of that kind
971 : ! Connectivity will be considered correct only if for each i:
972 : !
973 : ! mol(i,2) = mol(i,3)*mol(i,4)
974 : !
975 : ! If not, very probably, a bond is missing increase bondparm by 10% and let's
976 : ! check if the newest connectivity is bug free..
977 : !
978 :
979 23499 : ALLOCATE (mol_info_tmp(natom, 2))
980 :
981 7833 : itype = mol_map(1)
982 7833 : nsize = 1
983 7833 : idim = 1
984 7833 : mol_info_tmp(1, 1) = itype
985 209104 : DO i = 2, natom
986 209104 : IF (mol_map(i) /= itype) THEN
987 51205 : nsize = nsize + 1
988 51205 : itype = mol_map(i)
989 51205 : mol_info_tmp(nsize, 1) = itype
990 51205 : mol_info_tmp(nsize - 1, 2) = idim
991 51205 : idim = 1
992 : ELSE
993 150066 : idim = idim + 1
994 : END IF
995 : END DO
996 7833 : mol_info_tmp(nsize, 2) = idim
997 :
998 23499 : ALLOCATE (mol_info(nsize, 4))
999 141575 : mol_info(1:nsize, 1:2) = mol_info_tmp(1:nsize, 1:2)
1000 7833 : DEALLOCATE (mol_info_tmp)
1001 :
1002 66871 : DO i = 1, nsize
1003 59038 : mol_info(i, 3) = 0
1004 66871 : mol_info(i, 4) = 0
1005 : END DO
1006 : !
1007 15666 : ALLOCATE (icheck(natom))
1008 216937 : icheck = .FALSE.
1009 216871 : DO i = 1, natom
1010 209040 : IF (icheck(i)) CYCLE
1011 102800 : itype = mol_map_o(i)
1012 102800 : mol_natom = 0
1013 102800 : CALL give_back_molecule(icheck, bond_list, i, mol_natom, mol_map_o, mol_map_o(i))
1014 10748255 : DO j = 1, SIZE(mol_info)
1015 10542655 : IF (itype == mol_info(j, 1)) EXIT
1016 : END DO
1017 102800 : mol_info(j, 3) = mol_info(j, 3) + 1
1018 102800 : IF (mol_info(j, 4) == 0) mol_info(j, 4) = mol_natom
1019 110632 : IF (mol_info(j, 4) /= mol_natom) THEN
1020 : ! Two same molecules have been found with different number
1021 : ! of atoms. This usually indicates a missing bond in the
1022 : ! generated connectivity
1023 : ! Set connectivity to .false. EXIT and increase bondparm_factor by 1.05
1024 2 : conn_ok = .FALSE.
1025 2 : bondparm_factor = bondparm_factor*1.05_dp
1026 2 : IF (output_unit < 0) EXIT
1027 1 : WRITE (output_unit, '(/,T2,"GENERATE|",A)') " WARNING in connectivity generation!"
1028 : WRITE (output_unit, '(T2,"GENERATE|",A)') &
1029 : ' Two molecules/residues named ('//TRIM(id2str(itype))//') have different '// &
1030 1 : ' number of atoms.'
1031 1 : CALL integer_to_string(i, ctmp1)
1032 1 : CALL integer_to_string(mol_natom, ctmp2)
1033 1 : CALL integer_to_string(mol_info(j, 4), ctmp3)
1034 : WRITE (output_unit, '(T2,"GENERATE|",A)') ' Molecule starting at position ('// &
1035 : TRIM(ctmp1)//') has Nr. <'//TRIM(ctmp2)// &
1036 1 : '> of atoms.', ' while the other same molecules have Nr. <'// &
1037 2 : TRIM(ctmp3)//'> of atoms!'
1038 : WRITE (output_unit, '(T2,"GENERATE|",A)') &
1039 1 : ' Increasing bondparm_factor by 1.05.. An error was found in the generated', &
1040 2 : ' connectivity. Retry...'
1041 : WRITE (output_unit, '(T2,"GENERATE|",A,F11.6,A,/)') &
1042 1 : " Present value of BONDPARM_FACTOR (", bondparm_factor, " )."
1043 1 : EXIT
1044 : END IF
1045 : END DO
1046 :
1047 7833 : DEALLOCATE (icheck)
1048 7833 : DEALLOCATE (mol_info)
1049 7833 : DEALLOCATE (mol_map)
1050 7833 : DEALLOCATE (mol_map_o)
1051 7833 : DEALLOCATE (wrk)
1052 216937 : DO I = 1, natom
1053 216937 : DEALLOCATE (bond_list(I)%array1)
1054 : END DO
1055 7833 : DEALLOCATE (bond_list)
1056 7833 : CALL timestop(handle)
1057 7833 : END FUNCTION check_generate_mol
1058 :
1059 : ! **************************************************************************************************
1060 : !> \brief Add/Remove a bond to the generated list
1061 : !> Particularly useful for system with complex connectivity
1062 : !> \param section ...
1063 : !> \param Iarray1 ...
1064 : !> \param Iarray2 ...
1065 : !> \param Iarray3 ...
1066 : !> \param Iarray4 ...
1067 : !> \param nvar ...
1068 : !> \param topology ...
1069 : !> \param output_unit ...
1070 : !> \param is_impr ...
1071 : !> \author Teodoro Laino 09.2006
1072 : ! **************************************************************************************************
1073 27378 : SUBROUTINE connectivity_external_control(section, Iarray1, Iarray2, Iarray3, Iarray4, nvar, &
1074 : topology, output_unit, is_impr)
1075 : TYPE(section_vals_type), POINTER :: section
1076 : INTEGER, DIMENSION(:), POINTER :: Iarray1, Iarray2
1077 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: Iarray3, Iarray4
1078 : INTEGER, INTENT(INOUT) :: nvar
1079 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
1080 : INTEGER, INTENT(IN) :: output_unit
1081 : LOGICAL, INTENT(IN), OPTIONAL :: is_impr
1082 :
1083 : CHARACTER(LEN=8) :: fmt
1084 : INTEGER :: do_action, do_it, i, j, k, n_rep, &
1085 : n_rep_val, natom, new_size, nsize
1086 13689 : INTEGER, DIMENSION(:), POINTER :: atlist, Ilist1, Ilist2, Ilist3, Ilist4
1087 : LOGICAL :: explicit, ip3, ip4
1088 :
1089 13689 : natom = topology%natoms
1090 : ! Preliminary sort of arrays
1091 13689 : ip3 = PRESENT(Iarray3)
1092 13689 : ip4 = PRESENT(Iarray4)
1093 13689 : nsize = 2
1094 5544 : IF (ip3) nsize = nsize + 1
1095 13689 : IF (ip3 .AND. ip4) nsize = nsize + 1
1096 : ! Put the lists always in the canonical order
1097 13689 : CALL reorder_list_array(Iarray1, Iarray2, Iarray3, Iarray4, nsize, nvar)
1098 : ! Go on with external control
1099 13689 : CALL section_vals_get(section, explicit=explicit, n_repetition=n_rep)
1100 13689 : IF (explicit) THEN
1101 30 : NULLIFY (Ilist1, Ilist2, Ilist3, Ilist4, atlist)
1102 88 : ALLOCATE (Ilist1(nvar))
1103 58 : ALLOCATE (Ilist2(nvar))
1104 2702 : Ilist1 = Iarray1(1:nvar)
1105 2702 : Ilist2 = Iarray2(1:nvar)
1106 10 : SELECT CASE (nsize)
1107 : CASE (2) !do nothing
1108 : CASE (3)
1109 20 : ALLOCATE (Ilist3(nvar))
1110 706 : Ilist3 = Iarray3(1:nvar)
1111 : CASE (4)
1112 24 : ALLOCATE (Ilist3(nvar))
1113 24 : ALLOCATE (Ilist4(nvar))
1114 828 : Ilist3 = Iarray3(1:nvar)
1115 828 : Ilist4 = Iarray4(1:nvar)
1116 : CASE DEFAULT
1117 : ! Should never reach this point
1118 30 : CPABORT("")
1119 : END SELECT
1120 30 : CALL list_canonical_order(Ilist1, Ilist2, Ilist3, Ilist4, nsize, is_impr)
1121 : !
1122 98 : DO i = 1, n_rep
1123 68 : CALL section_vals_val_get(section, "ATOMS", i_rep_section=i, n_rep_val=n_rep_val)
1124 : CALL section_vals_val_get(section, "_SECTION_PARAMETERS_", i_rep_section=i, &
1125 68 : i_val=do_action)
1126 : !
1127 180 : DO j = 1, n_rep_val
1128 : CALL section_vals_val_get(section, "ATOMS", i_rep_section=i, i_rep_val=j, &
1129 82 : i_vals=atlist)
1130 82 : CPASSERT(SIZE(atlist) == nsize)
1131 82 : CALL integer_to_string(nsize - 1, fmt)
1132 : CALL check_element_list(do_it, do_action, atlist, Ilist1, Ilist2, Ilist3, Ilist4, &
1133 82 : is_impr)
1134 150 : IF (do_action == do_add) THEN
1135 : ! Add to the element to the list
1136 42 : IF (do_it > 0) THEN
1137 26 : nvar = nvar + 1
1138 26 : IF (output_unit > 0) THEN
1139 : WRITE (output_unit, '(T2,"ADD|",1X,A,I6,'//TRIM(fmt)//'(A,I6),A,T64,A,I6)') &
1140 13 : "element (", &
1141 48 : atlist(1), (",", atlist(k), k=2, nsize), ") added.", " NEW size::", nvar
1142 : END IF
1143 26 : IF (nvar > SIZE(Iarray1)) THEN
1144 2 : new_size = INT(5 + 1.2*nvar)
1145 2 : CALL reallocate(Iarray1, 1, new_size)
1146 2 : CALL reallocate(Iarray2, 1, new_size)
1147 0 : SELECT CASE (nsize)
1148 : CASE (3)
1149 0 : CALL reallocate(Iarray3, 1, new_size)
1150 : CASE (4)
1151 0 : CALL reallocate(Iarray3, 1, new_size)
1152 2 : CALL reallocate(Iarray4, 1, new_size)
1153 : END SELECT
1154 : END IF
1155 : ! Using Ilist instead of atlist the canonical order is preserved..
1156 428 : Iarray1(do_it + 1:nvar) = Iarray1(do_it:nvar - 1)
1157 428 : Iarray2(do_it + 1:nvar) = Iarray2(do_it:nvar - 1)
1158 26 : Iarray1(do_it) = Ilist1(do_it)
1159 26 : Iarray2(do_it) = Ilist2(do_it)
1160 2 : SELECT CASE (nsize)
1161 : CASE (3)
1162 86 : Iarray3(do_it + 1:nvar) = Iarray3(do_it:nvar - 1)
1163 2 : Iarray3(do_it) = Ilist3(do_it)
1164 : CASE (4)
1165 230 : Iarray3(do_it + 1:nvar) = Iarray3(do_it:nvar - 1)
1166 230 : Iarray4(do_it + 1:nvar) = Iarray4(do_it:nvar - 1)
1167 8 : Iarray3(do_it) = Ilist3(do_it)
1168 34 : Iarray4(do_it) = Ilist4(do_it)
1169 : END SELECT
1170 : ELSE
1171 16 : IF (output_unit > 0) THEN
1172 : WRITE (output_unit, '(T2,"ADD|",1X,A,I6,'//TRIM(fmt)//'(A,I6),A,T80,A)') &
1173 8 : "element (", &
1174 30 : atlist(1), (",", atlist(k), k=2, nsize), ") already found.", "X"
1175 : END IF
1176 : END IF
1177 : ELSE
1178 : ! Remove element from the list
1179 40 : IF (do_it > 0) THEN
1180 34 : nvar = nvar - 1
1181 34 : IF (output_unit > 0) THEN
1182 : WRITE (output_unit, '(T2,"RMV|",1X,A,I6,'//TRIM(fmt)//'(A,I6),A,T64,A,I6)') &
1183 17 : "element (", &
1184 73 : atlist(1), (",", atlist(k), k=2, nsize), ") removed.", " NEW size::", nvar
1185 : END IF
1186 506 : Iarray1(do_it:nvar) = Iarray1(do_it + 1:nvar + 1)
1187 506 : Iarray2(do_it:nvar) = Iarray2(do_it + 1:nvar + 1)
1188 34 : Iarray1(nvar + 1) = -HUGE(0)
1189 34 : Iarray2(nvar + 1) = -HUGE(0)
1190 16 : SELECT CASE (nsize)
1191 : CASE (3)
1192 260 : Iarray3(do_it:nvar) = Iarray3(do_it + 1:nvar + 1)
1193 16 : Iarray3(nvar + 1) = -HUGE(0)
1194 : CASE (4)
1195 146 : Iarray3(do_it:nvar) = Iarray3(do_it + 1:nvar + 1)
1196 146 : Iarray4(do_it:nvar) = Iarray4(do_it + 1:nvar + 1)
1197 14 : Iarray3(nvar + 1) = -HUGE(0)
1198 48 : Iarray4(nvar + 1) = -HUGE(0)
1199 : END SELECT
1200 : ELSE
1201 6 : IF (output_unit > 0) THEN
1202 : WRITE (output_unit, '(T2,"RMV|",1X,A,I6,'//TRIM(fmt)//'(A,I6),A,T80,A)') &
1203 3 : "element (", &
1204 10 : atlist(1), (",", atlist(k), k=2, nsize), ") not found.", "X"
1205 : END IF
1206 : END IF
1207 : END IF
1208 :
1209 : END DO
1210 : END DO
1211 30 : DEALLOCATE (Ilist1)
1212 30 : DEALLOCATE (Ilist2)
1213 10 : SELECT CASE (nsize)
1214 : CASE (2) ! do nothing
1215 : CASE (3)
1216 10 : DEALLOCATE (Ilist3)
1217 : CASE (4)
1218 12 : DEALLOCATE (Ilist3)
1219 12 : DEALLOCATE (Ilist4)
1220 : CASE DEFAULT
1221 : ! Should never reach this point
1222 30 : CPABORT("")
1223 : END SELECT
1224 : END IF
1225 13689 : END SUBROUTINE connectivity_external_control
1226 :
1227 : ! **************************************************************************************************
1228 : !> \brief Orders list in the canonical order: the extrema of the list are such
1229 : !> that the first extrema is always smaller or equal to the last extrema.
1230 : !> \param Ilist1 ...
1231 : !> \param Ilist2 ...
1232 : !> \param Ilist3 ...
1233 : !> \param Ilist4 ...
1234 : !> \param nsize ...
1235 : !> \param is_impr ...
1236 : !> \author Teodoro Laino 09.2006
1237 : ! **************************************************************************************************
1238 30 : SUBROUTINE list_canonical_order(Ilist1, Ilist2, Ilist3, Ilist4, nsize, is_impr)
1239 : INTEGER, DIMENSION(:), POINTER :: Ilist1, Ilist2
1240 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: Ilist3, Ilist4
1241 : INTEGER, INTENT(IN) :: nsize
1242 : LOGICAL, INTENT(IN), OPTIONAL :: is_impr
1243 :
1244 : INTEGER :: i, ss(3), tmp1, tmp2, tmp3, tt(3)
1245 : LOGICAL :: do_impr
1246 :
1247 30 : do_impr = .FALSE.
1248 30 : IF (PRESENT(is_impr)) do_impr = is_impr
1249 38 : SELECT CASE (nsize)
1250 : CASE (2)
1251 588 : DO i = 1, SIZE(Ilist1)
1252 580 : tmp1 = Ilist1(i)
1253 580 : tmp2 = Ilist2(i)
1254 580 : Ilist1(i) = MIN(tmp1, tmp2)
1255 588 : Ilist2(i) = MAX(tmp1, tmp2)
1256 : END DO
1257 : CASE (3)
1258 358 : DO i = 1, SIZE(Ilist1)
1259 348 : tmp1 = Ilist1(i)
1260 348 : tmp2 = Ilist3(i)
1261 348 : Ilist1(i) = MIN(tmp1, tmp2)
1262 358 : Ilist3(i) = MAX(tmp1, tmp2)
1263 : END DO
1264 : CASE (4)
1265 438 : DO i = 1, SIZE(Ilist1)
1266 420 : IF (.NOT. do_impr) THEN
1267 372 : tmp1 = Ilist1(i)
1268 372 : tmp2 = Ilist4(i)
1269 372 : Ilist1(i) = MIN(tmp1, tmp2)
1270 372 : IF (Ilist1(i) == tmp2) THEN
1271 0 : tmp3 = Ilist3(i)
1272 0 : Ilist3(i) = Ilist2(i)
1273 0 : Ilist2(i) = tmp3
1274 : END IF
1275 372 : Ilist4(i) = MAX(tmp1, tmp2)
1276 : ELSE
1277 36 : tt(1) = Ilist2(i)
1278 36 : tt(2) = Ilist3(i)
1279 36 : tt(3) = Ilist4(i)
1280 36 : CALL sort(tt, 3, ss)
1281 36 : Ilist2(i) = tt(1)
1282 36 : Ilist3(i) = tt(2)
1283 36 : Ilist4(i) = tt(3)
1284 : END IF
1285 : END DO
1286 : END SELECT
1287 :
1288 30 : END SUBROUTINE list_canonical_order
1289 :
1290 : ! **************************************************************************************************
1291 : !> \brief finds an element in the ordered list
1292 : !> \param do_it ...
1293 : !> \param do_action ...
1294 : !> \param atlist ...
1295 : !> \param Ilist1 ...
1296 : !> \param Ilist2 ...
1297 : !> \param Ilist3 ...
1298 : !> \param Ilist4 ...
1299 : !> \param is_impr ...
1300 : !> \author Teodoro Laino 09.2006
1301 : ! **************************************************************************************************
1302 82 : SUBROUTINE check_element_list(do_it, do_action, atlist, Ilist1, Ilist2, Ilist3, Ilist4, &
1303 : is_impr)
1304 : INTEGER, INTENT(OUT) :: do_it
1305 : INTEGER, INTENT(IN) :: do_action
1306 : INTEGER, DIMENSION(:), POINTER :: atlist, Ilist1, Ilist2
1307 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: Ilist3, Ilist4
1308 : LOGICAL, INTENT(IN), OPTIONAL :: is_impr
1309 :
1310 : INTEGER :: i, iend, istart, ndim, new_size, nsize, &
1311 : ss(3), tmp1, tmp2, tmp3, tt(3)
1312 : INTEGER, DIMENSION(4) :: tmp
1313 : LOGICAL :: do_impr, found
1314 :
1315 82 : do_impr = .FALSE.
1316 82 : IF (PRESENT(is_impr)) do_impr = is_impr
1317 82 : found = .FALSE.
1318 82 : nsize = SIZE(atlist)
1319 82 : ndim = SIZE(Ilist1)
1320 322 : DO i = 1, nsize
1321 322 : tmp(i) = atlist(i)
1322 : END DO
1323 28 : SELECT CASE (nsize)
1324 : CASE (2)
1325 28 : tmp1 = tmp(1)
1326 28 : tmp2 = tmp(2)
1327 28 : tmp(1) = MIN(tmp1, tmp2)
1328 28 : tmp(2) = MAX(tmp1, tmp2)
1329 : CASE (3)
1330 32 : tmp1 = tmp(1)
1331 32 : tmp2 = tmp(3)
1332 32 : tmp(1) = MIN(tmp1, tmp2)
1333 32 : tmp(3) = MAX(tmp1, tmp2)
1334 : CASE (4)
1335 82 : IF (.NOT. do_impr) THEN
1336 10 : tmp1 = tmp(1)
1337 10 : tmp2 = tmp(4)
1338 10 : tmp(1) = MIN(tmp1, tmp2)
1339 10 : IF (tmp(1) == tmp2) THEN
1340 6 : tmp3 = tmp(3)
1341 6 : tmp(3) = tmp(2)
1342 6 : tmp(2) = tmp3
1343 : END IF
1344 10 : tmp(4) = MAX(tmp1, tmp2)
1345 : ELSE
1346 12 : tt(1) = tmp(2)
1347 12 : tt(2) = tmp(3)
1348 12 : tt(3) = tmp(4)
1349 12 : CALL sort(tt, 3, ss)
1350 12 : tmp(2) = tt(1)
1351 12 : tmp(3) = tt(2)
1352 12 : tmp(4) = tt(3)
1353 : END IF
1354 : END SELECT
1355 : ! boundary to search
1356 1788 : DO istart = 1, ndim
1357 1788 : IF (Ilist1(istart) >= tmp(1)) EXIT
1358 : END DO
1359 : ! if nothing there stay within bounds
1360 82 : IF (istart <= ndim) THEN
1361 76 : IF (Ilist1(istart) > tmp(1) .AND. (istart /= 1)) istart = istart - 1
1362 : END IF
1363 222 : DO iend = istart, ndim
1364 222 : IF (Ilist1(iend) /= tmp(1)) EXIT
1365 : END DO
1366 82 : IF (iend == ndim + 1) iend = ndim
1367 : ! Final search in array
1368 : SELECT CASE (nsize)
1369 : CASE (2)
1370 40 : DO i = istart, iend
1371 28 : IF ((Ilist1(i) > tmp(1)) .OR. (Ilist2(i) > tmp(2))) EXIT
1372 40 : IF ((Ilist1(i) == tmp(1)) .AND. (Ilist2(i) == tmp(2))) THEN
1373 : found = .TRUE.
1374 : EXIT
1375 : END IF
1376 : END DO
1377 : CASE (3)
1378 40 : DO i = istart, iend
1379 40 : IF ((Ilist1(i) > tmp(1)) .OR. (Ilist2(i) > tmp(2)) .OR. (Ilist3(i) > tmp(3))) EXIT
1380 40 : IF ((Ilist1(i) == tmp(1)) .AND. (Ilist2(i) == tmp(2)) .AND. (Ilist3(i) == tmp(3))) THEN
1381 : found = .TRUE.
1382 : EXIT
1383 : END IF
1384 : END DO
1385 : CASE (4)
1386 106 : DO i = istart, iend
1387 22 : IF ((Ilist1(i) > tmp(1)) .OR. (Ilist2(i) > tmp(2)) .OR. (Ilist3(i) > tmp(3)) .OR. (Ilist4(i) > tmp(4))) EXIT
1388 : IF ((Ilist1(i) == tmp(1)) .AND. (Ilist2(i) == tmp(2)) &
1389 24 : .AND. (Ilist3(i) == tmp(3)) .AND. (Ilist4(i) == tmp(4))) THEN
1390 : found = .TRUE.
1391 : EXIT
1392 : END IF
1393 : END DO
1394 : END SELECT
1395 124 : SELECT CASE (do_action)
1396 : CASE (do_add)
1397 42 : IF (found) THEN
1398 16 : do_it = -i
1399 : ! Nothing to modify. Element already present
1400 : ! in this case ABS(do_it) gives the exact location of the element
1401 : ! in the list
1402 : ELSE
1403 : ! Let's add the element in the right place of the list.. so that we can keep the
1404 : ! canonical order
1405 : ! in this case do_it gives the index of the list with indexes bigger than
1406 : ! the one we're searching for
1407 : ! At the end do_it gives the exact location of the element in the canonical list
1408 26 : do_it = i
1409 26 : new_size = ndim + 1
1410 26 : CALL reallocate(Ilist1, 1, new_size)
1411 26 : CALL reallocate(Ilist2, 1, new_size)
1412 428 : Ilist1(i + 1:new_size) = Ilist1(i:ndim)
1413 428 : Ilist2(i + 1:new_size) = Ilist2(i:ndim)
1414 26 : Ilist1(i) = tmp(1)
1415 26 : Ilist2(i) = tmp(2)
1416 2 : SELECT CASE (nsize)
1417 : CASE (3)
1418 2 : CALL reallocate(Ilist3, 1, new_size)
1419 86 : Ilist3(i + 1:new_size) = Ilist3(i:ndim)
1420 2 : Ilist3(i) = tmp(3)
1421 : CASE (4)
1422 8 : CALL reallocate(Ilist3, 1, new_size)
1423 8 : CALL reallocate(Ilist4, 1, new_size)
1424 230 : Ilist3(i + 1:new_size) = Ilist3(i:ndim)
1425 230 : Ilist4(i + 1:new_size) = Ilist4(i:ndim)
1426 8 : Ilist3(i) = tmp(3)
1427 34 : Ilist4(i) = tmp(4)
1428 : END SELECT
1429 : END IF
1430 : CASE (do_remove)
1431 82 : IF (found) THEN
1432 34 : do_it = i
1433 : ! Let's delete the element in position do_it
1434 34 : new_size = ndim - 1
1435 506 : Ilist1(i:new_size) = Ilist1(i + 1:ndim)
1436 506 : Ilist2(i:new_size) = Ilist2(i + 1:ndim)
1437 34 : CALL reallocate(Ilist1, 1, new_size)
1438 34 : CALL reallocate(Ilist2, 1, new_size)
1439 16 : SELECT CASE (nsize)
1440 : CASE (3)
1441 260 : Ilist3(i:new_size) = Ilist3(i + 1:ndim)
1442 16 : CALL reallocate(Ilist3, 1, new_size)
1443 : CASE (4)
1444 146 : Ilist3(i:new_size) = Ilist3(i + 1:ndim)
1445 146 : Ilist4(i:new_size) = Ilist4(i + 1:ndim)
1446 14 : CALL reallocate(Ilist3, 1, new_size)
1447 48 : CALL reallocate(Ilist4, 1, new_size)
1448 : END SELECT
1449 : ELSE
1450 6 : do_it = -i
1451 : ! Nothing to modify. Element not present in the list
1452 : ! in this case ABS(do_it) gives the exact location of the element
1453 : ! in the list
1454 : END IF
1455 : END SELECT
1456 82 : END SUBROUTINE check_element_list
1457 :
1458 : ! **************************************************************************************************
1459 : !> \brief Adds a bond to the generated bond list
1460 : !> \param conn_info ...
1461 : !> \param atm1 ...
1462 : !> \param atm2 ...
1463 : !> \param n_bonds ...
1464 : !> \author Teodoro Laino 09.2006
1465 : ! **************************************************************************************************
1466 115318 : SUBROUTINE add_bonds_list(conn_info, atm1, atm2, n_bonds)
1467 : TYPE(connectivity_info_type), POINTER :: conn_info
1468 : INTEGER, INTENT(IN) :: atm1, atm2, n_bonds
1469 :
1470 : INTEGER :: new_size, old_size
1471 :
1472 115318 : old_size = SIZE(conn_info%bond_a)
1473 115318 : IF (n_bonds > old_size) THEN
1474 5886 : new_size = INT(5 + 1.2*old_size)
1475 5886 : CALL reallocate(conn_info%bond_a, 1, new_size)
1476 5886 : CALL reallocate(conn_info%bond_b, 1, new_size)
1477 : END IF
1478 115318 : conn_info%bond_a(n_bonds) = atm1
1479 115318 : conn_info%bond_b(n_bonds) = atm2
1480 115318 : END SUBROUTINE add_bonds_list
1481 :
1482 : ! **************************************************************************************************
1483 : !> \brief Using a list of bonds, generate a list of bends
1484 : !> \param topology ...
1485 : !> \param subsys_section ...
1486 : !> \author Teodoro Laino 09.2006
1487 : ! **************************************************************************************************
1488 18954 : SUBROUTINE topology_generate_bend(topology, subsys_section)
1489 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
1490 : TYPE(section_vals_type), POINTER :: subsys_section
1491 :
1492 : CHARACTER(len=*), PARAMETER :: routineN = 'topology_generate_bend'
1493 :
1494 : INTEGER :: handle, handle2, i, iw, natom, nbond, &
1495 : nsize, ntheta, output_unit
1496 9477 : TYPE(array1_list_type), DIMENSION(:), POINTER :: bond_list
1497 : TYPE(connectivity_info_type), POINTER :: conn_info
1498 : TYPE(cp_logger_type), POINTER :: logger
1499 : TYPE(section_vals_type), POINTER :: bend_section
1500 :
1501 9477 : NULLIFY (logger)
1502 18954 : logger => cp_get_default_logger()
1503 : iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/GENERATE_INFO", &
1504 9477 : extension=".subsysLog")
1505 9477 : CALL timeset(routineN, handle)
1506 9477 : output_unit = cp_logger_get_default_io_unit(logger)
1507 9477 : conn_info => topology%conn_info
1508 9477 : nbond = 0
1509 9477 : ntheta = 0
1510 9477 : natom = topology%natoms
1511 : ! This call is for connectivity off
1512 9477 : IF (ASSOCIATED(conn_info%bond_a)) THEN
1513 7829 : nbond = SIZE(conn_info%bond_a)
1514 : ELSE
1515 1648 : CALL reallocate(conn_info%bond_a, 1, nbond)
1516 1648 : CALL reallocate(conn_info%bond_b, 1, nbond)
1517 : END IF
1518 9477 : IF (nbond /= 0) THEN
1519 1848 : nsize = INT(5 + 1.2*ntheta)
1520 1848 : CALL reallocate(conn_info%theta_a, 1, nsize)
1521 1848 : CALL reallocate(conn_info%theta_b, 1, nsize)
1522 1848 : CALL reallocate(conn_info%theta_c, 1, nsize)
1523 : ! Get list of bonds to pre-process theta
1524 155780 : ALLOCATE (bond_list(natom))
1525 152084 : DO I = 1, natom
1526 152084 : ALLOCATE (bond_list(I)%array1(0))
1527 : END DO
1528 1848 : CALL reorder_structure(bond_list, conn_info%bond_a, conn_info%bond_b, nbond)
1529 : ! All the dirty job is handled by this routine.. for bends it_levl is equal 3
1530 1848 : CALL timeset(routineN//"_1", handle2)
1531 : CALL match_iterative_path(Iarray1=bond_list, &
1532 : Iarray2=bond_list, &
1533 : max_levl=3, &
1534 : nvar=ntheta, &
1535 : Oarray1=conn_info%theta_a, &
1536 : Oarray2=conn_info%theta_b, &
1537 1848 : Oarray3=conn_info%theta_c)
1538 1848 : CALL timestop(handle2)
1539 152084 : DO I = 1, natom
1540 152084 : DEALLOCATE (bond_list(I)%array1)
1541 : END DO
1542 1848 : DEALLOCATE (bond_list)
1543 1848 : IF (output_unit > 0) THEN
1544 985 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Preliminary Number of Bends generated:", &
1545 1970 : ntheta
1546 : END IF
1547 : ! External defined bends (useful for complex connectivity)
1548 1848 : bend_section => section_vals_get_subs_vals(subsys_section, "TOPOLOGY%GENERATE%ANGLE")
1549 : CALL connectivity_external_control(section=bend_section, &
1550 : Iarray1=conn_info%theta_a, &
1551 : Iarray2=conn_info%theta_b, &
1552 : Iarray3=conn_info%theta_c, &
1553 : nvar=ntheta, &
1554 : topology=topology, &
1555 3696 : output_unit=output_unit)
1556 : END IF
1557 : ! Resize arrays to their proper size..
1558 9477 : CALL reallocate(conn_info%theta_a, 1, ntheta)
1559 9477 : CALL reallocate(conn_info%theta_b, 1, ntheta)
1560 9477 : CALL reallocate(conn_info%theta_c, 1, ntheta)
1561 9477 : IF (output_unit > 0 .AND. ntheta > 0) THEN
1562 941 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Number of Bends generated:", &
1563 1882 : ntheta
1564 : END IF
1565 9477 : CALL timestop(handle)
1566 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
1567 9477 : "PRINT%TOPOLOGY_INFO/GENERATE_INFO")
1568 9477 : END SUBROUTINE topology_generate_bend
1569 :
1570 : !
1571 :
1572 : ! **************************************************************************************************
1573 : !> \brief Routine matching iteratively along a graph
1574 : !> \param Iarray1 ...
1575 : !> \param Iarray2 ...
1576 : !> \param Iarray3 ...
1577 : !> \param max_levl ...
1578 : !> \param Oarray1 ...
1579 : !> \param Oarray2 ...
1580 : !> \param Oarray3 ...
1581 : !> \param Oarray4 ...
1582 : !> \param Ilist ...
1583 : !> \param it_levl ...
1584 : !> \param nvar ...
1585 : !> \author Teodoro Laino 09.2006
1586 : ! **************************************************************************************************
1587 893952 : RECURSIVE SUBROUTINE match_iterative_path(Iarray1, Iarray2, Iarray3, &
1588 893952 : max_levl, Oarray1, Oarray2, Oarray3, Oarray4, Ilist, it_levl, nvar)
1589 : TYPE(array1_list_type), DIMENSION(:), POINTER :: Iarray1
1590 : TYPE(array1_list_type), DIMENSION(:), OPTIONAL, &
1591 : POINTER :: Iarray2, Iarray3
1592 : INTEGER, INTENT(IN) :: max_levl
1593 : INTEGER, DIMENSION(:), POINTER :: Oarray1, Oarray2
1594 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: Oarray3, Oarray4
1595 : INTEGER, DIMENSION(:), INTENT(INOUT), OPTIONAL :: Ilist
1596 : INTEGER, INTENT(IN), OPTIONAL :: it_levl
1597 : INTEGER, INTENT(INOUT) :: nvar
1598 :
1599 : INTEGER :: i, ind, j, my_levl, natom
1600 893952 : INTEGER, ALLOCATABLE, DIMENSION(:) :: my_list
1601 : LOGICAL :: check
1602 893952 : TYPE(array1_list_type), DIMENSION(:), POINTER :: wrk
1603 :
1604 893952 : check = max_levl >= 2 .AND. max_levl <= 4
1605 0 : CPASSERT(check)
1606 893952 : IF (.NOT. PRESENT(Ilist)) THEN
1607 0 : SELECT CASE (max_levl)
1608 : CASE (2)
1609 0 : CPASSERT(.NOT. PRESENT(Iarray2))
1610 0 : CPASSERT(.NOT. PRESENT(Iarray3))
1611 0 : CPASSERT(.NOT. PRESENT(Oarray3))
1612 0 : CPASSERT(.NOT. PRESENT(Oarray4))
1613 : CASE (3)
1614 1848 : CPASSERT(PRESENT(Iarray2))
1615 1848 : CPASSERT(.NOT. PRESENT(Iarray3))
1616 1848 : CPASSERT(PRESENT(Oarray3))
1617 1848 : CPASSERT(.NOT. PRESENT(Oarray4))
1618 : CASE (4)
1619 1848 : CPASSERT(PRESENT(Iarray2))
1620 1848 : CPASSERT(PRESENT(Iarray3))
1621 1848 : CPASSERT(PRESENT(Oarray3))
1622 5544 : CPASSERT(PRESENT(Oarray4))
1623 : END SELECT
1624 : END IF
1625 893952 : natom = SIZE(Iarray1)
1626 893952 : IF (.NOT. PRESENT(Ilist)) THEN
1627 : ! Start a new loop.. Only the first time the routine is called
1628 11088 : ALLOCATE (my_list(max_levl))
1629 304168 : DO i = 1, natom
1630 300472 : my_levl = 1
1631 1352124 : my_list = -1
1632 300472 : my_list(my_levl) = i
1633 : CALL match_iterative_path(Iarray1=Iarray1, &
1634 : Iarray2=Iarray2, &
1635 : Iarray3=Iarray3, &
1636 : it_levl=my_levl + 1, &
1637 : max_levl=max_levl, &
1638 : Oarray1=Oarray1, &
1639 : Oarray2=Oarray2, &
1640 : Oarray3=Oarray3, &
1641 : Oarray4=Oarray4, &
1642 : nvar=nvar, &
1643 304168 : Ilist=my_list)
1644 : END DO
1645 3696 : DEALLOCATE (my_list)
1646 : ELSE
1647 1190728 : SELECT CASE (it_levl)
1648 : CASE (2)
1649 300472 : wrk => Iarray1
1650 : CASE (3)
1651 425032 : wrk => Iarray2
1652 : CASE (4)
1653 890256 : wrk => Iarray3
1654 : END SELECT
1655 890256 : i = Ilist(it_levl - 1)
1656 2320112 : DO j = 1, SIZE(Iarray1(i)%array1)
1657 1429856 : ind = wrk(i)%array1(j)
1658 4576188 : IF (ANY(Ilist == ind)) CYCLE
1659 1729944 : IF (it_levl < max_levl) THEN
1660 589784 : Ilist(it_levl) = ind
1661 : CALL match_iterative_path(Iarray1=Iarray1, &
1662 : Iarray2=Iarray2, &
1663 : Iarray3=Iarray3, &
1664 : it_levl=it_levl + 1, &
1665 : max_levl=max_levl, &
1666 : Oarray1=Oarray1, &
1667 : Oarray2=Oarray2, &
1668 : Oarray3=Oarray3, &
1669 : Oarray4=Oarray4, &
1670 : nvar=nvar, &
1671 589784 : Ilist=Ilist)
1672 589784 : Ilist(it_levl) = -1
1673 249904 : ELSEIF (it_levl == max_levl) THEN
1674 249904 : IF (Ilist(1) > ind) CYCLE
1675 124952 : Ilist(it_levl) = ind
1676 124952 : nvar = nvar + 1
1677 0 : SELECT CASE (it_levl)
1678 : CASE (2)
1679 0 : IF (nvar > SIZE(Oarray1)) THEN
1680 0 : CALL reallocate(Oarray1, 1, INT(5 + 1.2*nvar))
1681 0 : CALL reallocate(Oarray2, 1, INT(5 + 1.2*nvar))
1682 : END IF
1683 0 : Oarray1(nvar) = Ilist(1)
1684 0 : Oarray2(nvar) = Ilist(2)
1685 : CASE (3)
1686 82376 : IF (nvar > SIZE(Oarray1)) THEN
1687 3160 : CALL reallocate(Oarray1, 1, INT(5 + 1.2*nvar))
1688 3160 : CALL reallocate(Oarray2, 1, INT(5 + 1.2*nvar))
1689 3160 : CALL reallocate(Oarray3, 1, INT(5 + 1.2*nvar))
1690 : END IF
1691 82376 : Oarray1(nvar) = Ilist(1)
1692 82376 : Oarray2(nvar) = Ilist(2)
1693 82376 : Oarray3(nvar) = Ilist(3)
1694 : CASE (4)
1695 42576 : IF (nvar > SIZE(Oarray1)) THEN
1696 1386 : CALL reallocate(Oarray1, 1, INT(5 + 1.2*nvar))
1697 1386 : CALL reallocate(Oarray2, 1, INT(5 + 1.2*nvar))
1698 1386 : CALL reallocate(Oarray3, 1, INT(5 + 1.2*nvar))
1699 1386 : CALL reallocate(Oarray4, 1, INT(5 + 1.2*nvar))
1700 : END IF
1701 42576 : Oarray1(nvar) = Ilist(1)
1702 42576 : Oarray2(nvar) = Ilist(2)
1703 42576 : Oarray3(nvar) = Ilist(3)
1704 42576 : Oarray4(nvar) = Ilist(4)
1705 : CASE DEFAULT
1706 : !should never reach this point
1707 124952 : CPABORT("")
1708 : END SELECT
1709 124952 : Ilist(it_levl) = -1
1710 : ELSE
1711 : !should never reach this point
1712 0 : CPABORT("")
1713 : END IF
1714 : END DO
1715 : END IF
1716 1787904 : END SUBROUTINE match_iterative_path
1717 :
1718 : !
1719 :
1720 : ! **************************************************************************************************
1721 : !> \brief The list of Urey-Bradley is equal to the list of bends
1722 : !> \param topology ...
1723 : !> \param subsys_section ...
1724 : ! **************************************************************************************************
1725 18954 : SUBROUTINE topology_generate_ub(topology, subsys_section)
1726 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
1727 : TYPE(section_vals_type), POINTER :: subsys_section
1728 :
1729 : CHARACTER(len=*), PARAMETER :: routineN = 'topology_generate_ub'
1730 :
1731 : INTEGER :: handle, itheta, iw, ntheta, output_unit
1732 : TYPE(connectivity_info_type), POINTER :: conn_info
1733 : TYPE(cp_logger_type), POINTER :: logger
1734 :
1735 9477 : NULLIFY (logger)
1736 9477 : logger => cp_get_default_logger()
1737 : iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/GENERATE_INFO", &
1738 9477 : extension=".subsysLog")
1739 9477 : output_unit = cp_logger_get_default_io_unit(logger)
1740 9477 : CALL timeset(routineN, handle)
1741 9477 : conn_info => topology%conn_info
1742 9477 : ntheta = SIZE(conn_info%theta_a)
1743 9477 : CALL reallocate(conn_info%ub_a, 1, ntheta)
1744 9477 : CALL reallocate(conn_info%ub_b, 1, ntheta)
1745 9477 : CALL reallocate(conn_info%ub_c, 1, ntheta)
1746 :
1747 91839 : DO itheta = 1, ntheta
1748 82362 : conn_info%ub_a(itheta) = conn_info%theta_a(itheta)
1749 82362 : conn_info%ub_b(itheta) = conn_info%theta_b(itheta)
1750 91839 : conn_info%ub_c(itheta) = conn_info%theta_c(itheta)
1751 : END DO
1752 9477 : IF (output_unit > 0 .AND. ntheta > 0) THEN
1753 941 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Number of UB generated:", &
1754 1882 : ntheta
1755 : END IF
1756 9477 : CALL timestop(handle)
1757 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
1758 9477 : "PRINT%TOPOLOGY_INFO/GENERATE_INFO")
1759 :
1760 9477 : END SUBROUTINE topology_generate_ub
1761 :
1762 : ! **************************************************************************************************
1763 : !> \brief Generate a list of torsions from bonds
1764 : !> \param topology ...
1765 : !> \param subsys_section ...
1766 : !> \author Teodoro Laino 09.2006
1767 : ! **************************************************************************************************
1768 18954 : SUBROUTINE topology_generate_dihe(topology, subsys_section)
1769 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
1770 : TYPE(section_vals_type), POINTER :: subsys_section
1771 :
1772 : CHARACTER(len=*), PARAMETER :: routineN = 'topology_generate_dihe'
1773 :
1774 : INTEGER :: handle, i, iw, natom, nbond, nphi, &
1775 : nsize, output_unit
1776 9477 : TYPE(array1_list_type), DIMENSION(:), POINTER :: bond_list
1777 : TYPE(connectivity_info_type), POINTER :: conn_info
1778 : TYPE(cp_logger_type), POINTER :: logger
1779 : TYPE(section_vals_type), POINTER :: torsion_section
1780 :
1781 9477 : NULLIFY (logger)
1782 18954 : logger => cp_get_default_logger()
1783 : iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/GENERATE_INFO", &
1784 9477 : extension=".subsysLog")
1785 9477 : output_unit = cp_logger_get_default_io_unit(logger)
1786 9477 : CALL timeset(routineN, handle)
1787 9477 : conn_info => topology%conn_info
1788 9477 : nphi = 0
1789 9477 : nbond = SIZE(conn_info%bond_a)
1790 9477 : IF (nbond /= 0) THEN
1791 1848 : nsize = INT(5 + 1.2*nphi)
1792 1848 : CALL reallocate(conn_info%phi_a, 1, nsize)
1793 1848 : CALL reallocate(conn_info%phi_b, 1, nsize)
1794 1848 : CALL reallocate(conn_info%phi_c, 1, nsize)
1795 1848 : CALL reallocate(conn_info%phi_d, 1, nsize)
1796 : ! Get list of bonds to pre-process phi
1797 1848 : natom = topology%natoms
1798 155780 : ALLOCATE (bond_list(natom))
1799 152084 : DO I = 1, natom
1800 152084 : ALLOCATE (bond_list(I)%array1(0))
1801 : END DO
1802 1848 : CALL reorder_structure(bond_list, conn_info%bond_a, conn_info%bond_b, nbond)
1803 : ! All the dirty job is handled by this routine.. for torsions it_levl is equal 4
1804 : CALL match_iterative_path(Iarray1=bond_list, &
1805 : Iarray2=bond_list, &
1806 : Iarray3=bond_list, &
1807 : max_levl=4, &
1808 : nvar=nphi, &
1809 : Oarray1=conn_info%phi_a, &
1810 : Oarray2=conn_info%phi_b, &
1811 : Oarray3=conn_info%phi_c, &
1812 1848 : Oarray4=conn_info%phi_d)
1813 152084 : DO I = 1, natom
1814 152084 : DEALLOCATE (bond_list(I)%array1)
1815 : END DO
1816 1848 : DEALLOCATE (bond_list)
1817 1848 : IF (output_unit > 0) THEN
1818 985 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Preliminary Number of Torsions generated:", &
1819 1970 : nphi
1820 : END IF
1821 : ! External defined torsions (useful for complex connectivity)
1822 1848 : torsion_section => section_vals_get_subs_vals(subsys_section, "TOPOLOGY%GENERATE%TORSION")
1823 : CALL connectivity_external_control(section=torsion_section, &
1824 : Iarray1=conn_info%phi_a, &
1825 : Iarray2=conn_info%phi_b, &
1826 : Iarray3=conn_info%phi_c, &
1827 : Iarray4=conn_info%phi_d, &
1828 : nvar=nphi, &
1829 : topology=topology, &
1830 1848 : output_unit=output_unit)
1831 : END IF
1832 : ! Resize arrays to their proper size..
1833 9477 : CALL reallocate(conn_info%phi_a, 1, nphi)
1834 9477 : CALL reallocate(conn_info%phi_b, 1, nphi)
1835 9477 : CALL reallocate(conn_info%phi_c, 1, nphi)
1836 9477 : CALL reallocate(conn_info%phi_d, 1, nphi)
1837 9477 : IF (output_unit > 0 .AND. nphi > 0) THEN
1838 220 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Number of Torsions generated:", &
1839 440 : nphi
1840 : END IF
1841 9477 : CALL timestop(handle)
1842 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
1843 9477 : "PRINT%TOPOLOGY_INFO/GENERATE_INFO")
1844 :
1845 9477 : END SUBROUTINE topology_generate_dihe
1846 :
1847 : ! **************************************************************************************************
1848 : !> \brief Using a list of bends, generate a list of impr
1849 : !> \param topology ...
1850 : !> \param subsys_section ...
1851 : !> \author Teodoro Laino 09.2006
1852 : ! **************************************************************************************************
1853 18954 : SUBROUTINE topology_generate_impr(topology, subsys_section)
1854 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
1855 : TYPE(section_vals_type), POINTER :: subsys_section
1856 :
1857 : CHARACTER(len=*), PARAMETER :: routineN = 'topology_generate_impr'
1858 :
1859 : CHARACTER(LEN=2) :: atm_symbol
1860 : INTEGER :: handle, i, ind, iw, j, natom, nbond, &
1861 : nimpr, nsize, output_unit
1862 : LOGICAL :: accept_impr
1863 9477 : TYPE(array1_list_type), DIMENSION(:), POINTER :: bond_list
1864 : TYPE(atom_info_type), POINTER :: atom_info
1865 : TYPE(connectivity_info_type), POINTER :: conn_info
1866 : TYPE(cp_logger_type), POINTER :: logger
1867 : TYPE(section_vals_type), POINTER :: impr_section
1868 :
1869 9477 : NULLIFY (logger)
1870 18954 : logger => cp_get_default_logger()
1871 : iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/GENERATE_INFO", &
1872 9477 : extension=".subsysLog")
1873 9477 : output_unit = cp_logger_get_default_io_unit(logger)
1874 9477 : CALL timeset(routineN, handle)
1875 9477 : atom_info => topology%atom_info
1876 9477 : conn_info => topology%conn_info
1877 9477 : natom = topology%natoms
1878 9477 : nimpr = 0
1879 9477 : nbond = SIZE(conn_info%bond_a)
1880 9477 : IF (nbond /= 0) THEN
1881 1848 : nsize = INT(5 + 1.2*nimpr)
1882 1848 : CALL reallocate(conn_info%impr_a, 1, nsize)
1883 1848 : CALL reallocate(conn_info%impr_b, 1, nsize)
1884 1848 : CALL reallocate(conn_info%impr_c, 1, nsize)
1885 1848 : CALL reallocate(conn_info%impr_d, 1, nsize)
1886 : ! Get list of bonds to pre-process phi
1887 155780 : ALLOCATE (bond_list(natom))
1888 152084 : DO I = 1, natom
1889 152084 : ALLOCATE (bond_list(I)%array1(0))
1890 : END DO
1891 1848 : CALL reorder_structure(bond_list, conn_info%bond_a, conn_info%bond_b, nbond)
1892 152084 : DO I = 1, natom
1893 : ! Count all atoms with three bonds
1894 152084 : IF (SIZE(bond_list(I)%array1) == 3) THEN
1895 : ! Problematic cases::
1896 : ! Nitrogen
1897 3334 : accept_impr = .TRUE.
1898 3334 : atm_symbol = TRIM(id2str(atom_info%id_element(i)))
1899 3334 : CALL uppercase(atm_symbol)
1900 3334 : IF (atm_symbol == "N ") THEN
1901 : accept_impr = .FALSE.
1902 : ! Impropers on Nitrogen only when there is another atom close to it
1903 : ! with other 3 bonds
1904 8696 : DO j = 1, 3
1905 6522 : ind = bond_list(I)%array1(j)
1906 8696 : IF (SIZE(bond_list(ind)%array1) == 3) accept_impr = .TRUE.
1907 : END DO
1908 : END IF
1909 2174 : IF (.NOT. accept_impr) CYCLE
1910 1910 : nimpr = nimpr + 1
1911 1910 : IF (nimpr > SIZE(conn_info%impr_a)) THEN
1912 136 : nsize = INT(5 + 1.2*nimpr)
1913 136 : CALL reallocate(conn_info%impr_a, 1, nsize)
1914 136 : CALL reallocate(conn_info%impr_b, 1, nsize)
1915 136 : CALL reallocate(conn_info%impr_c, 1, nsize)
1916 136 : CALL reallocate(conn_info%impr_d, 1, nsize)
1917 : END IF
1918 1910 : conn_info%impr_a(nimpr) = i
1919 1910 : conn_info%impr_b(nimpr) = bond_list(I)%array1(1)
1920 1910 : conn_info%impr_c(nimpr) = bond_list(I)%array1(2)
1921 1910 : conn_info%impr_d(nimpr) = bond_list(I)%array1(3)
1922 : END IF
1923 : END DO
1924 152084 : DO I = 1, natom
1925 152084 : DEALLOCATE (bond_list(I)%array1)
1926 : END DO
1927 1848 : DEALLOCATE (bond_list)
1928 : ! External defined impropers (useful for complex connectivity)
1929 1848 : impr_section => section_vals_get_subs_vals(subsys_section, "TOPOLOGY%GENERATE%IMPROPER")
1930 : CALL connectivity_external_control(section=impr_section, &
1931 : Iarray1=conn_info%impr_a, &
1932 : Iarray2=conn_info%impr_b, &
1933 : Iarray3=conn_info%impr_c, &
1934 : Iarray4=conn_info%impr_d, &
1935 : nvar=nimpr, &
1936 : topology=topology, &
1937 : output_unit=output_unit, &
1938 1848 : is_impr=.TRUE.)
1939 : END IF
1940 : ! Resize arrays to their proper size..
1941 9477 : CALL reallocate(conn_info%impr_a, 1, nimpr)
1942 9477 : CALL reallocate(conn_info%impr_b, 1, nimpr)
1943 9477 : CALL reallocate(conn_info%impr_c, 1, nimpr)
1944 9477 : CALL reallocate(conn_info%impr_d, 1, nimpr)
1945 9477 : IF (output_unit > 0 .AND. nimpr > 0) THEN
1946 43 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Number of Impropers generated:", &
1947 86 : nimpr
1948 : END IF
1949 9477 : CALL timestop(handle)
1950 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
1951 9477 : "PRINT%TOPOLOGY_INFO/GENERATE_INFO")
1952 :
1953 9477 : END SUBROUTINE topology_generate_impr
1954 :
1955 : ! **************************************************************************************************
1956 : !> \brief Using a list of torsion, generate a list of onfo
1957 : !> \param topology ...
1958 : !> \param subsys_section ...
1959 : ! **************************************************************************************************
1960 9477 : SUBROUTINE topology_generate_onfo(topology, subsys_section)
1961 : TYPE(topology_parameters_type), INTENT(INOUT) :: topology
1962 : TYPE(section_vals_type), POINTER :: subsys_section
1963 :
1964 : CHARACTER(len=*), PARAMETER :: routineN = 'topology_generate_onfo'
1965 :
1966 : INTEGER :: atom_a, atom_b, handle, i, ionfo, iw, &
1967 : natom, nbond, nphi, ntheta, output_unit
1968 9477 : TYPE(array1_list_type), DIMENSION(:), POINTER :: bond_list, phi_list, theta_list
1969 : TYPE(connectivity_info_type), POINTER :: conn_info
1970 : TYPE(cp_logger_type), POINTER :: logger
1971 :
1972 9477 : NULLIFY (logger)
1973 18954 : logger => cp_get_default_logger()
1974 : iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/GENERATE_INFO", &
1975 9477 : extension=".subsysLog")
1976 9477 : output_unit = cp_logger_get_default_io_unit(logger)
1977 9477 : CALL timeset(routineN, handle)
1978 :
1979 9477 : conn_info => topology%conn_info
1980 9477 : natom = topology%natoms
1981 :
1982 : ! Get list of bonds (sic). Get a list of bonded neighbors for every atom.
1983 299011 : ALLOCATE (bond_list(natom))
1984 280057 : DO i = 1, natom
1985 280057 : ALLOCATE (bond_list(i)%array1(0))
1986 : END DO
1987 9477 : nbond = SIZE(conn_info%bond_a)
1988 9477 : CALL reorder_structure(bond_list, conn_info%bond_a, conn_info%bond_b, nbond)
1989 :
1990 : ! Get a list of next nearest neighbors for every atom.
1991 299011 : ALLOCATE (theta_list(natom))
1992 280057 : DO i = 1, natom
1993 280057 : ALLOCATE (theta_list(i)%array1(0))
1994 : END DO
1995 9477 : ntheta = SIZE(conn_info%theta_a)
1996 9477 : CALL reorder_structure(theta_list, conn_info%theta_a, conn_info%theta_c, ntheta)
1997 :
1998 : ! Get a list of next next nearest neighbors for every atom.
1999 299011 : ALLOCATE (phi_list(natom))
2000 280057 : DO i = 1, natom
2001 280057 : ALLOCATE (phi_list(i)%array1(0))
2002 : END DO
2003 9477 : nphi = SIZE(conn_info%phi_a)
2004 9477 : CALL reorder_structure(phi_list, conn_info%phi_a, conn_info%phi_d, nphi)
2005 :
2006 : ! Allocate enough (possible too much)
2007 9477 : CALL reallocate(conn_info%onfo_a, 1, nphi)
2008 9477 : CALL reallocate(conn_info%onfo_b, 1, nphi)
2009 :
2010 9477 : ionfo = 0
2011 280057 : DO atom_a = 1, natom
2012 365205 : DO i = 1, SIZE(phi_list(atom_a)%array1)
2013 85148 : atom_b = phi_list(atom_a)%array1(i)
2014 : ! Avoid trivial duplicates.
2015 85148 : IF (atom_a > atom_b) CYCLE
2016 : ! Avoid onfo's in 4-rings.
2017 145238 : IF (ANY(atom_b == bond_list(atom_a)%array1)) CYCLE
2018 : ! Avoid onfo's in 5-rings.
2019 195108 : IF (ANY(atom_b == theta_list(atom_a)%array1)) CYCLE
2020 : ! Avoid onfo's in 6-rings.
2021 199640 : IF (ANY(atom_b == phi_list(atom_a)%array1(:i - 1))) CYCLE
2022 42182 : ionfo = ionfo + 1
2023 42182 : conn_info%onfo_a(ionfo) = atom_a
2024 355728 : conn_info%onfo_b(ionfo) = atom_b
2025 : END DO
2026 : END DO
2027 :
2028 : ! Reallocate such that just enough memory is used.
2029 9477 : CALL reallocate(conn_info%onfo_a, 1, ionfo)
2030 9477 : CALL reallocate(conn_info%onfo_b, 1, ionfo)
2031 :
2032 : ! Deallocate bond_list
2033 280057 : DO i = 1, natom
2034 280057 : DEALLOCATE (bond_list(i)%array1)
2035 : END DO
2036 9477 : DEALLOCATE (bond_list)
2037 : ! Deallocate theta_list
2038 280057 : DO i = 1, natom
2039 280057 : DEALLOCATE (theta_list(i)%array1)
2040 : END DO
2041 9477 : DEALLOCATE (theta_list)
2042 : ! Deallocate phi_list
2043 280057 : DO i = 1, natom
2044 280057 : DEALLOCATE (phi_list(i)%array1)
2045 : END DO
2046 9477 : DEALLOCATE (phi_list)
2047 :
2048 : ! Final output
2049 9477 : IF (output_unit > 0 .AND. ionfo > 0) THEN
2050 220 : WRITE (output_unit, '(T2,"GENERATE|",1X,A,T71,I10)') " Number of 1-4 interactions generated:", &
2051 440 : ionfo
2052 : END IF
2053 9477 : CALL timestop(handle)
2054 : CALL cp_print_key_finished_output(iw, logger, subsys_section, &
2055 9477 : "PRINT%TOPOLOGY_INFO/GENERATE_INFO")
2056 :
2057 18954 : END SUBROUTINE topology_generate_onfo
2058 :
2059 : END MODULE topology_generate_util
|