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