1!--------------------------------------------------------------------------------------------------!
2!   CP2K: A general program to perform molecular dynamics simulations                              !
3!   Copyright (C) 2000 - 2020  CP2K developers group                                               !
4!--------------------------------------------------------------------------------------------------!
5
6! **************************************************************************************************
7!> \brief Collection of subroutine needed for topology related things
8!> \par History
9!>     jgh (23-05-2004) Last atom of molecule information added
10! **************************************************************************************************
11
12MODULE topology_connectivity_util
13   USE cp_log_handling,                 ONLY: cp_get_default_logger,&
14                                              cp_logger_get_default_io_unit,&
15                                              cp_logger_type
16   USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
17                                              cp_print_key_unit_nr
18   USE force_field_kind_types,          ONLY: do_ff_charmm,&
19                                              do_ff_harmonic
20   USE input_constants,                 ONLY: do_conn_g87,&
21                                              do_conn_g96,&
22                                              do_conn_user
23   USE input_section_types,             ONLY: section_vals_type,&
24                                              section_vals_val_get
25   USE kinds,                           ONLY: default_string_length
26   USE memory_utilities,                ONLY: reallocate
27   USE molecule_kind_types,             ONLY: &
28        allocate_molecule_kind_set, atom_type, bend_type, bond_type, get_molecule_kind, impr_type, &
29        molecule_kind_type, opbend_type, set_molecule_kind, torsion_type, ub_type
30   USE molecule_types,                  ONLY: allocate_molecule_set,&
31                                              get_molecule,&
32                                              local_states_type,&
33                                              molecule_type,&
34                                              set_molecule,&
35                                              set_molecule_set
36   USE string_table,                    ONLY: id2str
37   USE topology_types,                  ONLY: atom_info_type,&
38                                              connectivity_info_type,&
39                                              topology_parameters_type
40   USE util,                            ONLY: sort
41#include "./base/base_uses.f90"
42
43   IMPLICIT NONE
44
45   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'topology_connectivity_util'
46
47   PRIVATE
48   PUBLIC :: topology_connectivity_pack, topology_conn_multiple
49
50CONTAINS
51
52! **************************************************************************************************
53!> \brief topology connectivity pack
54!> \param molecule_kind_set ...
55!> \param molecule_set ...
56!> \param topology ...
57!> \param subsys_section ...
58!> \par History 11/2009 (Louis Vanduyhuys): added Out of Plane bends based on
59!>                                      impropers in topology
60! **************************************************************************************************
61   SUBROUTINE topology_connectivity_pack(molecule_kind_set, molecule_set, &
62                                         topology, subsys_section)
63      TYPE(molecule_kind_type), DIMENSION(:), POINTER    :: molecule_kind_set
64      TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
65      TYPE(topology_parameters_type), INTENT(INOUT)      :: topology
66      TYPE(section_vals_type), POINTER                   :: subsys_section
67
68      CHARACTER(len=*), PARAMETER :: routineN = 'topology_connectivity_pack', &
69         routineP = moduleN//':'//routineN
70
71      CHARACTER(LEN=default_string_length)               :: name
72      INTEGER :: counter, first, handle, handle2, i, ibend, ibond, idim, iimpr, ikind, imol, &
73         inter_bends, inter_bonds, inter_imprs, inter_torsions, inter_ubs, intra_bends, &
74         intra_bonds, intra_imprs, intra_torsions, intra_ubs, inum, ires, istart_mol, istart_typ, &
75         itorsion, ityp, iub, iw, j, j1, j2, j3, j4, jind, last, min_index, natom, nelectron, &
76         nsgf, nval_tot1, nval_tot2, nvar1, nvar2, output_unit, stat
77      INTEGER, DIMENSION(:), POINTER :: c_var_a, c_var_b, c_var_c, c_var_d, c_var_type, &
78         first_list, last_list, map_atom_mol, map_atom_type, map_cvar_mol, map_cvars, map_var_mol, &
79         map_vars, molecule_list
80      INTEGER, DIMENSION(:, :), POINTER                  :: bnd_ctype, bnd_type
81      LOGICAL                                            :: found, found_last
82      TYPE(atom_info_type), POINTER                      :: atom_info
83      TYPE(atom_type), DIMENSION(:), POINTER             :: atom_list
84      TYPE(bend_type), DIMENSION(:), POINTER             :: bend_list
85      TYPE(bond_type), DIMENSION(:), POINTER             :: bond_list
86      TYPE(connectivity_info_type), POINTER              :: conn_info
87      TYPE(cp_logger_type), POINTER                      :: logger
88      TYPE(impr_type), DIMENSION(:), POINTER             :: impr_list
89      TYPE(local_states_type), DIMENSION(:), POINTER     :: lmi
90      TYPE(molecule_kind_type), POINTER                  :: molecule_kind
91      TYPE(molecule_type), POINTER                       :: molecule
92      TYPE(opbend_type), DIMENSION(:), POINTER           :: opbend_list
93      TYPE(torsion_type), DIMENSION(:), POINTER          :: torsion_list
94      TYPE(ub_type), DIMENSION(:), POINTER               :: ub_list
95
96      NULLIFY (logger)
97      logger => cp_get_default_logger()
98      output_unit = cp_logger_get_default_io_unit(logger)
99      iw = cp_print_key_unit_nr(logger, subsys_section, "PRINT%TOPOLOGY_INFO/UTIL_INFO", &
100                                extension=".subsysLog")
101      CALL timeset(routineN, handle)
102
103      atom_info => topology%atom_info
104      conn_info => topology%conn_info
105      ALLOCATE (map_atom_mol(topology%natoms))
106      ALLOCATE (map_atom_type(topology%natoms))
107      !-----------------------------------------------------------------------------
108      !-----------------------------------------------------------------------------
109      ! 1. Set the topology%[nmol_type,nmol,nmol_conn]
110      !-----------------------------------------------------------------------------
111      CALL timeset(routineN//"_1", handle2)
112      natom = topology%natoms
113      topology%nmol = 1
114      topology%nmol_type = 1
115      topology%nmol_conn = 0
116      map_atom_mol = -1
117      map_atom_type = -1
118      map_atom_mol(1) = 1
119      map_atom_type(1) = 1
120      DO i = 1, natom - 1
121         IF ((atom_info%map_mol_typ(i + 1) /= atom_info%map_mol_typ(i)) .OR. &
122             ((atom_info%map_mol_res(i + 1) /= atom_info%map_mol_res(i)) .AND. &
123              (.NOT. (topology%conn_type == do_conn_user)))) THEN
124            topology%nmol_type = topology%nmol_type + 1
125         END IF
126         map_atom_type(i + 1) = topology%nmol_type
127         IF ((atom_info%map_mol_typ(i + 1) /= atom_info%map_mol_typ(i)) .OR. &
128             (atom_info%map_mol_num(i + 1) /= atom_info%map_mol_num(i)) .OR. &
129             (atom_info%map_mol_res(i + 1) /= atom_info%map_mol_res(i))) THEN
130            topology%nmol = topology%nmol + 1
131         END IF
132         map_atom_mol(i + 1) = topology%nmol
133         IF ((atom_info%map_mol_typ(i + 1) == atom_info%map_mol_typ(i)) .AND. &
134             (atom_info%map_mol_num(i + 1) == atom_info%map_mol_num(i)) .AND. &
135             (atom_info%map_mol_res(i + 1) /= atom_info%map_mol_res(i))) THEN
136            topology%nmol_conn = topology%nmol_conn + 1
137         END IF
138      END DO
139      IF (iw > 0) WRITE (iw, *) "topology%nmol ::", topology%nmol
140      IF (iw > 0) WRITE (iw, *) "topology%nmol_type ::", topology%nmol_type
141      IF (iw > 0) WRITE (iw, *) "topology%nmol_conn ::", topology%nmol_conn
142      CALL timestop(handle2)
143      !-----------------------------------------------------------------------------
144      !-----------------------------------------------------------------------------
145      ! 1.1 Clean the temporary arrays to avoid quadratic loops around
146      !     after this fix all topology_pack will be linear scaling
147      !-----------------------------------------------------------------------------
148      CALL timeset(routineN//"_1.1", handle2)
149      istart_mol = map_atom_mol(1)
150      istart_typ = map_atom_type(1)
151      DO i = 2, natom
152         IF ((map_atom_mol(i) /= istart_mol) .AND. (map_atom_type(i) == istart_typ)) THEN
153            map_atom_mol(i) = -map_atom_mol(i)
154         ELSE IF (map_atom_type(i) /= istart_typ) THEN
155            istart_mol = map_atom_mol(i)
156            istart_typ = map_atom_type(i)
157         END IF
158      END DO
159      CALL timestop(handle2)
160      !-----------------------------------------------------------------------------
161      !-----------------------------------------------------------------------------
162      ! 2. Allocate the molecule_kind_set
163      !-----------------------------------------------------------------------------
164      CALL timeset(routineN//"_2", handle2)
165      IF (topology%nmol_type <= 0) THEN
166         CPABORT("No molecule kind defined")
167      ELSE
168         NULLIFY (molecule_kind_set)
169         i = topology%nmol_type
170         CALL allocate_molecule_kind_set(molecule_kind_set, i)
171         IF (iw > 0) WRITE (iw, *) "    Allocated molecule_kind_set, Dimenstion of ", &
172            SIZE(molecule_kind_set)
173      END IF
174      CALL timestop(handle2)
175      !-----------------------------------------------------------------------------
176      !-----------------------------------------------------------------------------
177      ! 3. Allocate the molecule_set
178      !-----------------------------------------------------------------------------
179      CALL timeset(routineN//"_3", handle2)
180      IF (topology%nmol <= 0) THEN
181         CPABORT("No molecule defined")
182      ELSE
183         NULLIFY (molecule_set)
184         i = topology%nmol
185         CALL allocate_molecule_set(molecule_set, i)
186         IF (iw > 0) WRITE (iw, *) "    Allocated molecule_set, dimension of ", &
187            topology%nmol
188      END IF
189      CALL timestop(handle2)
190      !-----------------------------------------------------------------------------
191      !-----------------------------------------------------------------------------
192      ! 4. Set the molecule_kind_set%[kind_number,name,nsgf,nelectron]
193      !-----------------------------------------------------------------------------
194      CALL timeset(routineN//"_4", handle2)
195      natom = topology%natoms
196      ikind = -1
197      DO i = 1, natom
198         IF (ikind /= map_atom_type(i)) THEN
199            ikind = map_atom_type(i)
200            molecule_kind => molecule_kind_set(ikind)
201            nsgf = 0
202            nelectron = 0
203            name = TRIM(id2str(atom_info%id_molname(i)))
204            CALL set_molecule_kind(molecule_kind=molecule_kind, &
205                                   kind_number=ikind, &
206                                   molname_generated=topology%molname_generated, &
207                                   name=TRIM(name), &
208                                   nsgf=nsgf, &
209                                   nelectron=nelectron)
210         END IF
211      END DO
212      CALL timestop(handle2)
213      !-----------------------------------------------------------------------------
214      !-----------------------------------------------------------------------------
215      ! 5. Set the molecule_list for molecule_kind in molecule_kind_set
216      !-----------------------------------------------------------------------------
217      CALL timeset(routineN//"_5", handle2)
218      natom = topology%natoms
219      ikind = map_atom_type(1)
220      imol = ABS(map_atom_mol(1))
221      counter = 0
222      DO i = 1, natom - 1
223         IF (ikind /= map_atom_type(i + 1)) THEN
224            found = .TRUE.
225            found_last = .FALSE.
226            imol = ABS(map_atom_mol(i))
227         ELSEIF (ikind == topology%nmol_type) THEN
228            found = .TRUE.
229            found_last = .TRUE.
230            imol = ABS(map_atom_mol(natom))
231         ELSE
232            found = .FALSE.
233            found_last = .FALSE.
234         END IF
235
236         IF (found) THEN
237            ALLOCATE (molecule_list(imol - counter))
238            DO j = 1, SIZE(molecule_list)
239               molecule_list(j) = j + counter
240            END DO
241            molecule_kind => molecule_kind_set(ikind)
242            CALL set_molecule_kind(molecule_kind=molecule_kind, &
243                                   molecule_list=molecule_list)
244            IF (iw > 0) WRITE (iw, *) "      molecule_list", ikind, molecule_list(:)
245            IF (found_last) EXIT
246            counter = imol
247            ikind = map_atom_type(i + 1)
248         END IF
249      END DO
250      ! Treat separately the case in which the last atom is also a molecule
251      IF (i == natom) THEN
252         imol = ABS(map_atom_mol(natom))
253         ! Last atom is also a molecule by itself
254         ALLOCATE (molecule_list(imol - counter))
255         DO j = 1, SIZE(molecule_list)
256            molecule_list(j) = j + counter
257         END DO
258         molecule_kind => molecule_kind_set(ikind)
259         CALL set_molecule_kind(molecule_kind=molecule_kind, &
260                                molecule_list=molecule_list)
261         IF (iw > 0) WRITE (iw, *) "      molecule_list", ikind, molecule_list(:)
262      END IF
263      CALL timestop(handle2)
264      !-----------------------------------------------------------------------------
265      !-----------------------------------------------------------------------------
266      ! 6. Set the molecule_set(imol)%molecule_kind via set_molecule
267      !-----------------------------------------------------------------------------
268      CALL timeset(routineN//"_6", handle2)
269      DO ikind = 1, SIZE(molecule_kind_set)
270         molecule_kind => molecule_kind_set(ikind)
271         CALL get_molecule_kind(molecule_kind=molecule_kind, &
272                                molecule_list=molecule_list)
273         DO i = 1, SIZE(molecule_list)
274            molecule => molecule_set(molecule_list(i))
275            CALL set_molecule(molecule, molecule_kind=molecule_kind)
276         END DO
277      END DO
278      CALL timestop(handle2)
279      !-----------------------------------------------------------------------------
280      !-----------------------------------------------------------------------------
281      ! 7. Set the molecule_set(imol)%[first_atom,last_atom] via set_molecule_set
282      !-----------------------------------------------------------------------------
283      ALLOCATE (first_list(SIZE(molecule_set)))
284      ALLOCATE (last_list(SIZE(molecule_set)))
285      CALL timeset(routineN//"_7", handle2)
286      first_list(:) = 0
287      last_list(:) = 0
288      ityp = atom_info%map_mol_typ(1)
289      inum = atom_info%map_mol_num(1)
290      ires = atom_info%map_mol_res(1)
291      imol = 1
292      first_list(1) = 1
293      DO j = 2, natom
294         IF ((atom_info%map_mol_typ(j) /= ityp) .OR. &
295             (atom_info%map_mol_num(j) /= inum) .OR. &
296             (atom_info%map_mol_res(j) /= ires)) THEN
297            ityp = atom_info%map_mol_typ(j)
298            inum = atom_info%map_mol_num(j)
299            ires = atom_info%map_mol_res(j)
300            imol = imol + 1
301            first_list(imol) = j
302         END IF
303      END DO
304      CPASSERT(imol == topology%nmol)
305      DO ikind = 1, topology%nmol - 1
306         last_list(ikind) = first_list(ikind + 1) - 1
307      END DO
308      last_list(topology%nmol) = topology%natoms
309      CALL set_molecule_set(molecule_set, first_list, last_list)
310      CALL timestop(handle2)
311      !-----------------------------------------------------------------------------
312      !-----------------------------------------------------------------------------
313      ! 8. Set and NULLIFY the molecule_set(imol)%lmi via set_molecule_set
314      !-----------------------------------------------------------------------------
315      CALL timeset(routineN//"_8", handle2)
316      DO imol = 1, SIZE(molecule_set)
317         molecule => molecule_set(imol)
318         NULLIFY (lmi)
319         CALL set_molecule(molecule, lmi=lmi)
320      END DO
321      CALL timestop(handle2)
322      !-----------------------------------------------------------------------------
323      !-----------------------------------------------------------------------------
324      ! 9. Set the atom_list for molecule_kind in molecule_kind_set (PART 1)
325      !-----------------------------------------------------------------------------
326      CALL timeset(routineN//"_9", handle2)
327      counter = 0
328      DO imol = 1, SIZE(molecule_set)
329         molecule => molecule_set(imol)
330         molecule_kind => molecule_set(imol)%molecule_kind
331         CALL get_molecule_kind(molecule_kind=molecule_kind, &
332                                kind_number=i)
333         IF (counter /= i) THEN
334            counter = i
335            CALL get_molecule(molecule=molecule, &
336                              first_atom=first, last_atom=last)
337            natom = 0
338            IF (first /= 0 .AND. last /= 0) natom = last - first + 1
339            ALLOCATE (atom_list(natom))
340            DO i = 1, natom
341               !Atomic kind information will be filled in (PART 2)
342               NULLIFY (atom_list(i)%atomic_kind)
343               atom_list(i)%id_name = atom_info%id_atmname(i + first - 1)
344               IF (iw > 0) WRITE (iw, '(5X,A,3I5,1X,A5)') "atom_list ", &
345                  imol, counter, i, TRIM(id2str(atom_list(i)%id_name))
346            END DO
347            CALL set_molecule_kind(molecule_kind=molecule_kind, atom_list=atom_list)
348         END IF
349      END DO
350      CALL timestop(handle2)
351      !-----------------------------------------------------------------------------
352      !-----------------------------------------------------------------------------
353      ! 10. Set the molecule_kind%[nbond,bond_list] via set_molecule_kind
354      !-----------------------------------------------------------------------------
355      CALL timeset(routineN//"_10", handle2)
356      ! First map bonds on molecules
357      nvar1 = 0
358      nvar2 = 0
359      NULLIFY (map_vars, map_cvars, bnd_type, bnd_ctype)
360      IF (ASSOCIATED(conn_info%bond_a)) nvar1 = SIZE(conn_info%bond_a)
361      IF (ASSOCIATED(conn_info%c_bond_a)) nvar2 = SIZE(conn_info%c_bond_a)
362      nval_tot1 = nvar1
363      nval_tot2 = 0
364      ALLOCATE (map_var_mol(nvar1))
365      ALLOCATE (map_cvar_mol(nvar2))
366      map_var_mol = -1
367      map_cvar_mol = -1
368      DO i = 1, nvar1
369         j1 = map_atom_mol(conn_info%bond_a(i))
370         j2 = map_atom_mol(conn_info%bond_b(i))
371         IF (j1 == j2) THEN
372            IF (j1 > 0) map_var_mol(i) = map_atom_type(conn_info%bond_a(i))
373         END IF
374      END DO
375      DO i = 1, nvar2
376         min_index = MIN(conn_info%c_bond_a(i), conn_info%c_bond_b(i))
377         j1 = map_atom_mol(min_index)
378         IF (j1 > 0) map_cvar_mol(i) = map_atom_type(min_index)
379      END DO
380      CALL find_bnd_typ(topology%nmol_type, map_vars, map_var_mol, bnd_type, nvar1)
381      CALL find_bnd_typ(topology%nmol_type, map_cvars, map_cvar_mol, bnd_ctype, nvar2)
382      DO i = 1, topology%nmol_type
383         intra_bonds = 0
384         inter_bonds = 0
385         IF (ALL(bnd_type(:, i) > 0)) THEN
386            intra_bonds = bnd_type(2, i) - bnd_type(1, i) + 1
387         END IF
388         IF (ALL(bnd_ctype(:, i) > 0)) THEN
389            inter_bonds = bnd_ctype(2, i) - bnd_ctype(1, i) + 1
390         END IF
391         ibond = intra_bonds + inter_bonds
392         IF (iw > 0) THEN
393            WRITE (iw, *) "    Total number bonds for molecule type ", i, " :", ibond
394            WRITE (iw, *) "    intra (bonds inside  molecules) :: ", intra_bonds
395            WRITE (iw, *) "    inter (bonds between molecules) :: ", inter_bonds
396         END IF
397         molecule_kind => molecule_kind_set(i)
398         nval_tot2 = nval_tot2 + ibond*SIZE(molecule_kind%molecule_list)
399
400         ALLOCATE (bond_list(ibond))
401         ibond = 0
402         DO j = bnd_type(1, i), bnd_type(2, i)
403            IF (j == 0) CYCLE
404            ibond = ibond + 1
405            jind = map_vars(j)
406            first = first_list(map_atom_mol(conn_info%bond_a(jind)))
407            bond_list(ibond)%a = conn_info%bond_a(jind) - first + 1
408            bond_list(ibond)%b = conn_info%bond_b(jind) - first + 1
409            ! Set by default id_type to charmm and modify when handling the forcefield
410            bond_list(ibond)%id_type = do_ff_charmm
411            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
412               bond_list(ibond)%itype = conn_info%bond_type(jind)
413            END IF
414            !point this to the right bond_kind_type if using force field
415            NULLIFY (bond_list(ibond)%bond_kind)
416            IF (iw > 0) THEN
417               WRITE (iw, '(7X,A,I3,1X,A,I5,I5,1X,A,I5,I5)') "molecule_kind", &
418                  i, "  intra bond", &
419                  conn_info%bond_a(jind), &
420                  conn_info%bond_b(jind), &
421                  "offset number at", &
422                  conn_info%bond_a(jind) - first + 1, &
423                  conn_info%bond_b(jind) - first + 1
424            END IF
425         END DO
426         DO j = bnd_ctype(1, i), bnd_ctype(2, i)
427            IF (j == 0) CYCLE
428            ibond = ibond + 1
429            jind = map_cvars(j)
430            min_index = MIN(conn_info%c_bond_a(jind), conn_info%c_bond_b(jind))
431            first = first_list(map_atom_mol(min_index))
432            bond_list(ibond)%a = conn_info%c_bond_a(jind) - first + 1
433            bond_list(ibond)%b = conn_info%c_bond_b(jind) - first + 1
434            ! Set by default id_type to charmm and modify when handling the forcefield
435            bond_list(ibond)%id_type = do_ff_charmm
436            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
437               bond_list(ibond)%itype = conn_info%c_bond_type(jind)
438            END IF
439            !point this to the right bond_kind_type if using force field
440            NULLIFY (bond_list(ibond)%bond_kind)
441            IF (iw > 0) THEN
442               WRITE (iw, '(7X,A,I3,1X,A,I5,I5,1X,A,I5,I5)') "molecule_kind", &
443                  i, " inter bond", &
444                  conn_info%c_bond_a(jind), &
445                  conn_info%c_bond_b(jind), &
446                  "offset number at", &
447                  conn_info%c_bond_a(jind) - first + 1, &
448                  conn_info%c_bond_b(jind) - first + 1
449            END IF
450         END DO
451         CALL set_molecule_kind(molecule_kind=molecule_kind, &
452                                nbond=SIZE(bond_list), bond_list=bond_list)
453      END DO
454      IF ((nval_tot1 /= nval_tot2) .AND. (output_unit > 0)) THEN
455         WRITE (output_unit, '(/)')
456         WRITE (output_unit, '(T5,A)') "ERROR| Mismatching found between the total number  of atoms"
457         WRITE (output_unit, '(T5,A)') "ERROR| and the number of atoms computed multiplying the Nr."
458         WRITE (output_unit, '(T5,A)') "ERROR| of molecules by the  number of atoms  building  that"
459         WRITE (output_unit, '(T5,A)') "ERROR| kind of molecule."
460         WRITE (output_unit, '(T5,A)') "ERROR| This happens when the connectivity is wrongly  built"
461         WRITE (output_unit, '(T5,A)') "ERROR| One example could be two same kind of molecules have"
462         WRITE (output_unit, '(T5,A)') "ERROR| a different number of atoms. Check the connectivity!"
463      END IF
464      CPASSERT(nval_tot1 == nval_tot2)
465      DEALLOCATE (map_var_mol)
466      DEALLOCATE (map_cvar_mol)
467      DEALLOCATE (map_vars)
468      DEALLOCATE (map_cvars)
469      DEALLOCATE (bnd_type)
470      DEALLOCATE (bnd_ctype)
471      CALL timestop(handle2)
472      !-----------------------------------------------------------------------------
473      !-----------------------------------------------------------------------------
474      ! 11. Set the molecule_kind%[nbend,bend_list] via set_molecule_kind
475      !-----------------------------------------------------------------------------
476      ! Allocate c_var_a, c_var_b, c_var_c, c_var_type
477      CALL timeset(routineN//"_11_pre", handle2)
478      idim = 0
479      ALLOCATE (c_var_a(idim))
480      ALLOCATE (c_var_b(idim))
481      ALLOCATE (c_var_c(idim))
482      found = ASSOCIATED(conn_info%theta_type)
483      IF (found) THEN
484         ALLOCATE (c_var_type(idim))
485      END IF
486      IF (ASSOCIATED(conn_info%c_bond_a) .AND. ASSOCIATED(conn_info%theta_a)) THEN
487         DO j = 1, SIZE(conn_info%theta_a)
488            j1 = map_atom_mol(conn_info%theta_a(j))
489            j2 = map_atom_mol(conn_info%theta_b(j))
490            j3 = map_atom_mol(conn_info%theta_c(j))
491            IF (j1 /= j2 .OR. j2 /= j3) THEN
492               idim = idim + 1
493            END IF
494         END DO
495         CALL reallocate(c_var_a, 1, idim)
496         CALL reallocate(c_var_b, 1, idim)
497         CALL reallocate(c_var_c, 1, idim)
498         IF (found) THEN
499            CALL reallocate(c_var_type, 1, idim)
500         END IF
501         idim = 0
502         DO j = 1, SIZE(conn_info%theta_a)
503            j1 = map_atom_mol(conn_info%theta_a(j))
504            j2 = map_atom_mol(conn_info%theta_b(j))
505            j3 = map_atom_mol(conn_info%theta_c(j))
506            IF (j1 /= j2 .OR. j2 /= j3) THEN
507               idim = idim + 1
508               c_var_a(idim) = conn_info%theta_a(j)
509               c_var_b(idim) = conn_info%theta_b(j)
510               c_var_c(idim) = conn_info%theta_c(j)
511               IF (found) THEN
512                  c_var_type(idim) = conn_info%theta_type(j)
513               END IF
514            END IF
515         END DO
516      END IF
517      CALL timestop(handle2)
518      CALL timeset(routineN//"_11", handle2)
519      ! map bends on molecules
520      nvar1 = 0
521      nvar2 = 0
522      NULLIFY (map_vars, map_cvars, bnd_type, bnd_ctype)
523      IF (ASSOCIATED(conn_info%theta_a)) nvar1 = SIZE(conn_info%theta_a)
524      IF (ASSOCIATED(c_var_a)) nvar2 = SIZE(c_var_a)
525      nval_tot1 = nvar1
526      nval_tot2 = 0
527      ALLOCATE (map_var_mol(nvar1))
528      ALLOCATE (map_cvar_mol(nvar2))
529      map_var_mol = -1
530      map_cvar_mol = -1
531      DO i = 1, nvar1
532         j1 = map_atom_mol(conn_info%theta_a(i))
533         j2 = map_atom_mol(conn_info%theta_b(i))
534         j3 = map_atom_mol(conn_info%theta_c(i))
535         IF (j1 == j2 .AND. j2 == j3) THEN
536            IF (j1 > 0) map_var_mol(i) = map_atom_type(conn_info%theta_a(i))
537         END IF
538      END DO
539      DO i = 1, nvar2
540         min_index = MIN(c_var_a(i), c_var_b(i), c_var_c(i))
541         j1 = map_atom_mol(min_index)
542         IF (j1 > 0) map_cvar_mol(i) = map_atom_type(min_index)
543      END DO
544      CALL find_bnd_typ(topology%nmol_type, map_vars, map_var_mol, bnd_type, nvar1)
545      CALL find_bnd_typ(topology%nmol_type, map_cvars, map_cvar_mol, bnd_ctype, nvar2)
546      DO i = 1, topology%nmol_type
547         intra_bends = 0
548         inter_bends = 0
549         IF (ALL(bnd_type(:, i) > 0)) THEN
550            intra_bends = bnd_type(2, i) - bnd_type(1, i) + 1
551         END IF
552         IF (ALL(bnd_ctype(:, i) > 0)) THEN
553            inter_bends = bnd_ctype(2, i) - bnd_ctype(1, i) + 1
554         END IF
555         ibend = intra_bends + inter_bends
556         IF (iw > 0) THEN
557            WRITE (iw, *) "    Total number of angles for molecule type ", i, " :", ibend
558            WRITE (iw, *) "    intra (angles inside  molecules) :: ", intra_bends
559            WRITE (iw, *) "    inter (angles between molecules) :: ", inter_bends
560         END IF
561         molecule_kind => molecule_kind_set(i)
562         nval_tot2 = nval_tot2 + ibend*SIZE(molecule_kind%molecule_list)
563         ALLOCATE (bend_list(ibend))
564         ibend = 0
565         DO j = bnd_type(1, i), bnd_type(2, i)
566            IF (j == 0) CYCLE
567            ibend = ibend + 1
568            jind = map_vars(j)
569            first = first_list(map_atom_mol(conn_info%theta_a(jind)))
570            bend_list(ibend)%a = conn_info%theta_a(jind) - first + 1
571            bend_list(ibend)%b = conn_info%theta_b(jind) - first + 1
572            bend_list(ibend)%c = conn_info%theta_c(jind) - first + 1
573            ! Set by default id_type to charmm and modify when handling the forcefield
574            bend_list(ibend)%id_type = do_ff_charmm
575            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
576               bend_list(ibend)%itype = conn_info%theta_type(jind)
577            END IF
578            !point this to the right bend_kind_type if using force field
579            NULLIFY (bend_list(ibend)%bend_kind)
580            IF (iw > 0) THEN
581               WRITE (iw, '(7X,A,I3,1X,A,I5,I5,I5,1X,A,I5,I5,I5)') &
582                  "molecule_kind", ikind, "intra bend", &
583                  conn_info%theta_a(jind), &
584                  conn_info%theta_b(jind), &
585                  conn_info%theta_c(jind), &
586                  "offset number at", &
587                  conn_info%theta_a(jind) - first + 1, &
588                  conn_info%theta_b(jind) - first + 1, &
589                  conn_info%theta_c(jind) - first + 1
590            END IF
591         END DO
592         DO j = bnd_ctype(1, i), bnd_ctype(2, i)
593            IF (j == 0) CYCLE
594            ibend = ibend + 1
595            jind = map_cvars(j)
596            min_index = MIN(c_var_a(jind), c_var_b(jind), c_var_c(jind))
597            first = first_list(map_atom_mol(min_index))
598            bend_list(ibend)%a = c_var_a(jind) - first + 1
599            bend_list(ibend)%b = c_var_b(jind) - first + 1
600            bend_list(ibend)%c = c_var_c(jind) - first + 1
601            ! Set by default id_type to charmm and modify when handling the forcefield
602            bend_list(ibend)%id_type = do_ff_charmm
603            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
604               bend_list(ibend)%itype = c_var_type(jind)
605            END IF
606            !point this to the right bend_kind_type if using force field
607            NULLIFY (bend_list(ibend)%bend_kind)
608            IF (iw > 0) THEN
609               WRITE (iw, '(7X,A,I3,1X,A,I5,I5,I5,1X,A,I5,I5,I5)') &
610                  "molecule_kind", ikind, "inter bend", &
611                  c_var_a(jind), &
612                  c_var_b(jind), &
613                  c_var_c(jind), &
614                  "offset number at", &
615                  c_var_a(jind) - first + 1, &
616                  c_var_b(jind) - first + 1, &
617                  c_var_c(jind) - first + 1
618            END IF
619         END DO
620         CALL set_molecule_kind(molecule_kind=molecule_kind, &
621                                nbend=SIZE(bend_list), bend_list=bend_list)
622      END DO
623      CPASSERT(nval_tot1 == nval_tot2)
624      DEALLOCATE (map_var_mol)
625      DEALLOCATE (map_cvar_mol)
626      DEALLOCATE (map_vars)
627      DEALLOCATE (map_cvars)
628      DEALLOCATE (bnd_type)
629      DEALLOCATE (bnd_ctype)
630      DEALLOCATE (c_var_a)
631      DEALLOCATE (c_var_b)
632      DEALLOCATE (c_var_c)
633      IF (found) THEN
634         DEALLOCATE (c_var_type)
635      END IF
636      CALL timestop(handle2)
637      !-----------------------------------------------------------------------------
638      !-----------------------------------------------------------------------------
639      ! 12. Set the molecule_kind%[nub,ub_list] via set_molecule_kind
640      !-----------------------------------------------------------------------------
641      CALL timeset(routineN//"_12_pre", handle2)
642      idim = 0
643      ALLOCATE (c_var_a(idim))
644      ALLOCATE (c_var_b(idim))
645      ALLOCATE (c_var_c(idim))
646      IF (ASSOCIATED(conn_info%c_bond_a) .AND. ASSOCIATED(conn_info%ub_a)) THEN
647         DO j = 1, SIZE(conn_info%ub_a)
648            j1 = map_atom_mol(conn_info%ub_a(j))
649            j2 = map_atom_mol(conn_info%ub_b(j))
650            j3 = map_atom_mol(conn_info%ub_c(j))
651            IF (j1 /= j2 .OR. j2 /= j3) THEN
652               idim = idim + 1
653            END IF
654         END DO
655         CALL reallocate(c_var_a, 1, idim)
656         CALL reallocate(c_var_b, 1, idim)
657         CALL reallocate(c_var_c, 1, idim)
658         idim = 0
659         DO j = 1, SIZE(conn_info%ub_a)
660            j1 = map_atom_mol(conn_info%ub_a(j))
661            j2 = map_atom_mol(conn_info%ub_b(j))
662            j3 = map_atom_mol(conn_info%ub_c(j))
663            IF (j1 /= j2 .OR. j2 /= j3) THEN
664               idim = idim + 1
665               c_var_a(idim) = conn_info%ub_a(j)
666               c_var_b(idim) = conn_info%ub_b(j)
667               c_var_c(idim) = conn_info%ub_c(j)
668            END IF
669         END DO
670      END IF
671      CALL timestop(handle2)
672      CALL timeset(routineN//"_12", handle2)
673      ! map UBs on molecules
674      nvar1 = 0
675      nvar2 = 0
676      NULLIFY (map_vars, map_cvars, bnd_type, bnd_ctype)
677      IF (ASSOCIATED(conn_info%ub_a)) nvar1 = SIZE(conn_info%ub_a)
678      IF (ASSOCIATED(c_var_a)) nvar2 = SIZE(c_var_a)
679      nval_tot1 = nvar1
680      nval_tot2 = 0
681      ALLOCATE (map_var_mol(nvar1))
682      ALLOCATE (map_cvar_mol(nvar2))
683      map_var_mol = -1
684      map_cvar_mol = -1
685      DO i = 1, nvar1
686         j1 = map_atom_mol(conn_info%ub_a(i))
687         j2 = map_atom_mol(conn_info%ub_b(i))
688         j3 = map_atom_mol(conn_info%ub_c(i))
689         IF (j1 == j2 .AND. j2 == j3) THEN
690            IF (j1 > 0) map_var_mol(i) = map_atom_type(conn_info%ub_a(i))
691         END IF
692      END DO
693      DO i = 1, nvar2
694         min_index = MIN(c_var_a(i), c_var_b(i), c_var_c(i))
695         j1 = map_atom_mol(min_index)
696         IF (j1 > 0) map_cvar_mol(i) = map_atom_type(min_index)
697      END DO
698      CALL find_bnd_typ(topology%nmol_type, map_vars, map_var_mol, bnd_type, nvar1)
699      CALL find_bnd_typ(topology%nmol_type, map_cvars, map_cvar_mol, bnd_ctype, nvar2)
700      DO i = 1, topology%nmol_type
701         intra_ubs = 0
702         inter_ubs = 0
703         IF (ALL(bnd_type(:, i) > 0)) THEN
704            intra_ubs = bnd_type(2, i) - bnd_type(1, i) + 1
705         END IF
706         IF (ALL(bnd_ctype(:, i) > 0)) THEN
707            inter_ubs = bnd_ctype(2, i) - bnd_ctype(1, i) + 1
708         END IF
709         iub = intra_ubs + inter_ubs
710         IF (iw > 0) THEN
711            WRITE (iw, *) "    Total number of Urey-Bradley for molecule type ", i, " :", iub
712            WRITE (iw, *) "    intra (UB inside  molecules) :: ", intra_ubs
713            WRITE (iw, *) "    inter (UB between molecules) :: ", inter_ubs
714         END IF
715         molecule_kind => molecule_kind_set(i)
716         nval_tot2 = nval_tot2 + iub*SIZE(molecule_kind%molecule_list)
717         ALLOCATE (ub_list(iub))
718         iub = 0
719         DO j = bnd_type(1, i), bnd_type(2, i)
720            IF (j == 0) CYCLE
721            iub = iub + 1
722            jind = map_vars(j)
723            first = first_list(map_atom_mol(conn_info%ub_a(jind)))
724            ub_list(iub)%a = conn_info%ub_a(jind) - first + 1
725            ub_list(iub)%b = conn_info%ub_b(jind) - first + 1
726            ub_list(iub)%c = conn_info%ub_c(jind) - first + 1
727            ub_list(iub)%id_type = do_ff_charmm
728            !point this to the right ub_kind_type if using force field
729            NULLIFY (ub_list(iub)%ub_kind)
730            IF (iw > 0) THEN
731               WRITE (iw, '(7X,A,I3,1X,A,I5,I5,I5,1X,A,I5,I5,I5)') &
732                  "molecule_kind", i, "intra UB", &
733                  conn_info%ub_a(jind), &
734                  conn_info%ub_b(jind), &
735                  conn_info%ub_c(jind), &
736                  "offset number at", &
737                  conn_info%ub_a(jind) - first + 1, &
738                  conn_info%ub_b(jind) - first + 1, &
739                  conn_info%ub_c(jind) - first + 1
740            END IF
741         END DO
742         DO j = bnd_ctype(1, i), bnd_ctype(2, i)
743            IF (j == 0) CYCLE
744            iub = iub + 1
745            jind = map_cvars(j)
746            min_index = MIN(c_var_a(jind), c_var_b(jind), c_var_c(jind))
747            first = first_list(map_atom_mol(min_index))
748            ub_list(iub)%a = c_var_a(jind) - first + 1
749            ub_list(iub)%b = c_var_b(jind) - first + 1
750            ub_list(iub)%c = c_var_c(jind) - first + 1
751            ub_list(iub)%id_type = do_ff_charmm
752            !point this to the right ub_kind_type if using force field
753            NULLIFY (ub_list(iub)%ub_kind)
754            IF (iw > 0) THEN
755               WRITE (iw, '(7X,A,I3,1X,A,I5,I5,I5,1X,A,I5,I5,I5)') &
756                  "molecule_kind", i, "inter UB", &
757                  c_var_a(jind), &
758                  c_var_b(jind), &
759                  c_var_c(jind), &
760                  "offset number at", &
761                  c_var_a(jind) - first + 1, &
762                  c_var_b(jind) - first + 1, &
763                  c_var_c(jind) - first + 1
764            END IF
765         END DO
766         CALL set_molecule_kind(molecule_kind=molecule_kind, &
767                                nub=SIZE(ub_list), ub_list=ub_list)
768      END DO
769      CPASSERT(nval_tot1 == nval_tot2)
770      DEALLOCATE (map_var_mol)
771      DEALLOCATE (map_cvar_mol)
772      DEALLOCATE (map_vars)
773      DEALLOCATE (map_cvars)
774      DEALLOCATE (bnd_type)
775      DEALLOCATE (bnd_ctype)
776      DEALLOCATE (c_var_a)
777      DEALLOCATE (c_var_b)
778      DEALLOCATE (c_var_c)
779      CALL timestop(handle2)
780      !-----------------------------------------------------------------------------
781      !-----------------------------------------------------------------------------
782      ! 13. Set the molecule_kind%[ntorsion,torsion_list] via set_molecule_kind
783      !-----------------------------------------------------------------------------
784      ! Allocate c_var_a, c_var_b, c_var_c, c_var_d, c_var_type
785      CALL timeset(routineN//"_13_pre", handle2)
786      idim = 0
787      ALLOCATE (c_var_a(idim))
788      ALLOCATE (c_var_b(idim))
789      ALLOCATE (c_var_c(idim))
790      ALLOCATE (c_var_d(idim))
791      found = ASSOCIATED(conn_info%phi_type)
792      IF (found) THEN
793         ALLOCATE (c_var_type(idim))
794      END IF
795      IF (ASSOCIATED(conn_info%c_bond_a) .AND. ASSOCIATED(conn_info%phi_a)) THEN
796         DO j = 1, SIZE(conn_info%phi_a)
797            j1 = map_atom_mol(conn_info%phi_a(j))
798            j2 = map_atom_mol(conn_info%phi_b(j))
799            j3 = map_atom_mol(conn_info%phi_c(j))
800            j4 = map_atom_mol(conn_info%phi_d(j))
801            IF (j1 /= j2 .OR. j2 /= j3 .OR. j3 /= j4) THEN
802               idim = idim + 1
803            END IF
804         END DO
805         CALL reallocate(c_var_a, 1, idim)
806         CALL reallocate(c_var_b, 1, idim)
807         CALL reallocate(c_var_c, 1, idim)
808         CALL reallocate(c_var_d, 1, idim)
809         IF (found) THEN
810            CALL reallocate(c_var_type, 1, idim)
811         END IF
812         idim = 0
813         DO j = 1, SIZE(conn_info%phi_a)
814            j1 = map_atom_mol(conn_info%phi_a(j))
815            j2 = map_atom_mol(conn_info%phi_b(j))
816            j3 = map_atom_mol(conn_info%phi_c(j))
817            j4 = map_atom_mol(conn_info%phi_d(j))
818            IF (j1 /= j2 .OR. j2 /= j3 .OR. j3 /= j4) THEN
819               idim = idim + 1
820               c_var_a(idim) = conn_info%phi_a(j)
821               c_var_b(idim) = conn_info%phi_b(j)
822               c_var_c(idim) = conn_info%phi_c(j)
823               c_var_d(idim) = conn_info%phi_d(j)
824               IF (found) THEN
825                  c_var_type(idim) = conn_info%phi_type(j)
826               END IF
827            END IF
828         END DO
829      END IF
830      CALL timestop(handle2)
831      CALL timeset(routineN//"_13", handle2)
832      ! map torsions on molecules
833      nvar1 = 0
834      nvar2 = 0
835      NULLIFY (map_vars, map_cvars, bnd_type, bnd_ctype)
836      IF (ASSOCIATED(conn_info%phi_a)) nvar1 = SIZE(conn_info%phi_a)
837      IF (ASSOCIATED(c_var_a)) nvar2 = SIZE(c_var_a)
838      nval_tot1 = nvar1
839      nval_tot2 = 0
840      ALLOCATE (map_var_mol(nvar1))
841      ALLOCATE (map_cvar_mol(nvar2))
842      map_var_mol = -1
843      map_cvar_mol = -1
844      DO i = 1, nvar1
845         j1 = map_atom_mol(conn_info%phi_a(i))
846         j2 = map_atom_mol(conn_info%phi_b(i))
847         j3 = map_atom_mol(conn_info%phi_c(i))
848         j4 = map_atom_mol(conn_info%phi_d(i))
849         IF (j1 == j2 .AND. j2 == j3 .AND. j3 == j4) THEN
850            IF (j1 > 0) map_var_mol(i) = map_atom_type(conn_info%phi_a(i))
851         END IF
852      END DO
853      DO i = 1, nvar2
854         min_index = MIN(c_var_a(i), c_var_b(i), c_var_c(i), c_var_d(i))
855         j1 = map_atom_mol(min_index)
856         IF (j1 > 0) map_cvar_mol(i) = map_atom_type(min_index)
857      END DO
858      CALL find_bnd_typ(topology%nmol_type, map_vars, map_var_mol, bnd_type, nvar1)
859      CALL find_bnd_typ(topology%nmol_type, map_cvars, map_cvar_mol, bnd_ctype, nvar2)
860      DO i = 1, topology%nmol_type
861         intra_torsions = 0
862         inter_torsions = 0
863         IF (ALL(bnd_type(:, i) > 0)) THEN
864            intra_torsions = bnd_type(2, i) - bnd_type(1, i) + 1
865         END IF
866         IF (ALL(bnd_ctype(:, i) > 0)) THEN
867            inter_torsions = bnd_ctype(2, i) - bnd_ctype(1, i) + 1
868         END IF
869         itorsion = intra_torsions + inter_torsions
870         IF (iw > 0) THEN
871            WRITE (iw, *) "    Total number of torsions for molecule type ", i, " :", itorsion
872            WRITE (iw, *) "    intra (torsions inside  molecules) :: ", intra_torsions
873            WRITE (iw, *) "    inter (torsions between molecules) :: ", inter_torsions
874         END IF
875         molecule_kind => molecule_kind_set(i)
876         nval_tot2 = nval_tot2 + itorsion*SIZE(molecule_kind%molecule_list)
877         ALLOCATE (torsion_list(itorsion))
878         itorsion = 0
879         DO j = bnd_type(1, i), bnd_type(2, i)
880            IF (j == 0) CYCLE
881            itorsion = itorsion + 1
882            jind = map_vars(j)
883            first = first_list(map_atom_mol(conn_info%phi_a(jind)))
884            torsion_list(itorsion)%a = conn_info%phi_a(jind) - first + 1
885            torsion_list(itorsion)%b = conn_info%phi_b(jind) - first + 1
886            torsion_list(itorsion)%c = conn_info%phi_c(jind) - first + 1
887            torsion_list(itorsion)%d = conn_info%phi_d(jind) - first + 1
888            ! Set by default id_type to charmm and modify when handling the forcefield
889            torsion_list(itorsion)%id_type = do_ff_charmm
890            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
891               torsion_list(itorsion)%itype = conn_info%phi_type(jind)
892            END IF
893            !point this to the right torsion_kind_type if using force field
894            NULLIFY (torsion_list(itorsion)%torsion_kind)
895            IF (iw > 0) THEN
896               WRITE (iw, '(7X,A,I3,1X,A,I4,I4,I4,I4,1X,A,I4,I4,I4,I4)') &
897                  "molecule_kind", i, "intra TOR", &
898                  conn_info%phi_a(jind), &
899                  conn_info%phi_b(jind), &
900                  conn_info%phi_c(jind), &
901                  conn_info%phi_d(jind), &
902                  "offset number at", &
903                  conn_info%phi_a(jind) - first + 1, &
904                  conn_info%phi_b(jind) - first + 1, &
905                  conn_info%phi_c(jind) - first + 1, &
906                  conn_info%phi_d(jind) - first + 1
907            END IF
908         END DO
909         DO j = bnd_ctype(1, i), bnd_ctype(2, i)
910            IF (j == 0) CYCLE
911            itorsion = itorsion + 1
912            jind = map_cvars(j)
913            min_index = MIN(c_var_a(jind), c_var_b(jind), c_var_c(jind), c_var_d(jind))
914            first = first_list(map_atom_mol(min_index))
915            torsion_list(itorsion)%a = c_var_a(jind) - first + 1
916            torsion_list(itorsion)%b = c_var_b(jind) - first + 1
917            torsion_list(itorsion)%c = c_var_c(jind) - first + 1
918            torsion_list(itorsion)%d = c_var_d(jind) - first + 1
919            ! Set by default id_type to charmm and modify when handling the forcefield
920            torsion_list(itorsion)%id_type = do_ff_charmm
921            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
922               torsion_list(itorsion)%itype = c_var_type(jind)
923            END IF
924            !point this to the right torsion_kind_type if using force field
925            NULLIFY (torsion_list(itorsion)%torsion_kind)
926            IF (iw > 0) THEN
927               WRITE (iw, '(7X,A,I3,1X,A,I4,I4,I4,I4,1X,A,I4,I4,I4,I4)') &
928                  "molecule_kind", i, "inter TOR", &
929                  c_var_a(jind), &
930                  c_var_b(jind), &
931                  c_var_c(jind), &
932                  c_var_d(jind), &
933                  "offset number at", &
934                  c_var_a(jind) - first + 1, &
935                  c_var_b(jind) - first + 1, &
936                  c_var_c(jind) - first + 1, &
937                  c_var_d(jind) - first + 1
938            END IF
939         END DO
940         CALL set_molecule_kind(molecule_kind=molecule_kind, &
941                                ntorsion=SIZE(torsion_list), torsion_list=torsion_list)
942      END DO
943      CPASSERT(nval_tot1 == nval_tot2)
944      DEALLOCATE (map_var_mol)
945      DEALLOCATE (map_cvar_mol)
946      DEALLOCATE (map_vars)
947      DEALLOCATE (map_cvars)
948      DEALLOCATE (bnd_type)
949      DEALLOCATE (bnd_ctype)
950      DEALLOCATE (c_var_a)
951      DEALLOCATE (c_var_b)
952      DEALLOCATE (c_var_c)
953      DEALLOCATE (c_var_d)
954      IF (found) THEN
955         DEALLOCATE (c_var_type)
956      END IF
957      CALL timestop(handle2)
958      !-----------------------------------------------------------------------------
959      !-----------------------------------------------------------------------------
960      ! 14. Set the molecule_kind%[nimpr,impr_list] via set_molecule_kind
961      !     Also set the molecule_kind%[nopbend,opbend_list]
962      !-----------------------------------------------------------------------------
963      ! Allocate c_var_a, c_var_b, c_var_c, c_var_d, c_var_type
964      CALL timeset(routineN//"_14_pre", handle2)
965      idim = 0
966      ALLOCATE (c_var_a(idim))
967      ALLOCATE (c_var_b(idim))
968      ALLOCATE (c_var_c(idim))
969      ALLOCATE (c_var_d(idim))
970      found = ASSOCIATED(conn_info%impr_type)
971      IF (found) THEN
972         ALLOCATE (c_var_type(idim))
973      END IF
974      IF (ASSOCIATED(conn_info%c_bond_a) .AND. ASSOCIATED(conn_info%impr_a)) THEN
975         DO j = 1, SIZE(conn_info%impr_a)
976            j1 = map_atom_mol(conn_info%impr_a(j))
977            j2 = map_atom_mol(conn_info%impr_b(j))
978            j3 = map_atom_mol(conn_info%impr_c(j))
979            j4 = map_atom_mol(conn_info%impr_d(j))
980            IF (j1 /= j2 .OR. j2 /= j3 .OR. j3 /= j4) THEN
981               idim = idim + 1
982            END IF
983         END DO
984         CALL reallocate(c_var_a, 1, idim)
985         CALL reallocate(c_var_b, 1, idim)
986         CALL reallocate(c_var_c, 1, idim)
987         CALL reallocate(c_var_d, 1, idim)
988         IF (found) THEN
989            CALL reallocate(c_var_type, 1, idim)
990         END IF
991         idim = 0
992         DO j = 1, SIZE(conn_info%impr_a)
993            j1 = map_atom_mol(conn_info%impr_a(j))
994            j2 = map_atom_mol(conn_info%impr_b(j))
995            j3 = map_atom_mol(conn_info%impr_c(j))
996            j4 = map_atom_mol(conn_info%impr_d(j))
997            IF (j1 /= j2 .OR. j2 /= j3 .OR. j3 /= j4) THEN
998               idim = idim + 1
999               c_var_a(idim) = conn_info%impr_a(j)
1000               c_var_b(idim) = conn_info%impr_b(j)
1001               c_var_c(idim) = conn_info%impr_c(j)
1002               c_var_d(idim) = conn_info%impr_d(j)
1003               IF (found) THEN
1004                  c_var_type(idim) = conn_info%impr_type(j)
1005               END IF
1006            END IF
1007         END DO
1008      END IF
1009      CALL timestop(handle2)
1010      CALL timeset(routineN//"_14", handle2)
1011      ! map imprs on molecules
1012      nvar1 = 0
1013      nvar2 = 0
1014      NULLIFY (map_vars, map_cvars, bnd_type, bnd_ctype)
1015      IF (ASSOCIATED(conn_info%impr_a)) nvar1 = SIZE(conn_info%impr_a)
1016      IF (ASSOCIATED(c_var_a)) nvar2 = SIZE(c_var_a)
1017      nval_tot1 = nvar1
1018      nval_tot2 = 0
1019      ALLOCATE (map_var_mol(nvar1))
1020      ALLOCATE (map_cvar_mol(nvar2))
1021      map_var_mol = -1
1022      map_cvar_mol = -1
1023      DO i = 1, nvar1
1024         j1 = map_atom_mol(conn_info%impr_a(i))
1025         j2 = map_atom_mol(conn_info%impr_b(i))
1026         j3 = map_atom_mol(conn_info%impr_c(i))
1027         j4 = map_atom_mol(conn_info%impr_d(i))
1028         IF (j1 == j2 .AND. j2 == j3 .AND. j3 == j4) THEN
1029            IF (j1 > 0) map_var_mol(i) = map_atom_type(conn_info%impr_a(i))
1030         END IF
1031      END DO
1032      DO i = 1, nvar2
1033         min_index = MIN(c_var_a(i), c_var_b(i), c_var_c(i), c_var_d(i))
1034         j1 = map_atom_mol(min_index)
1035         IF (j1 > 0) map_cvar_mol(i) = map_atom_type(min_index)
1036      END DO
1037      CALL find_bnd_typ(topology%nmol_type, map_vars, map_var_mol, bnd_type, nvar1)
1038      CALL find_bnd_typ(topology%nmol_type, map_cvars, map_cvar_mol, bnd_ctype, nvar2)
1039      DO i = 1, topology%nmol_type
1040         intra_imprs = 0
1041         inter_imprs = 0
1042         IF (ALL(bnd_type(:, i) > 0)) THEN
1043            intra_imprs = bnd_type(2, i) - bnd_type(1, i) + 1
1044         END IF
1045         IF (ALL(bnd_ctype(:, i) > 0)) THEN
1046            inter_imprs = bnd_ctype(2, i) - bnd_ctype(1, i) + 1
1047         END IF
1048         iimpr = intra_imprs + inter_imprs
1049         IF (iw > 0) THEN
1050            WRITE (iw, *) "    Total number of imprs for molecule type ", i, " :", iimpr
1051            WRITE (iw, *) "    intra (imprs inside  molecules) :: ", intra_imprs
1052            WRITE (iw, *) "    inter (imprs between molecules) :: ", inter_imprs
1053            WRITE (iw, *) "    Total number of opbends for molecule type ", i, " :", iimpr
1054            WRITE (iw, *) "    intra (opbends inside  molecules) :: ", intra_imprs
1055            WRITE (iw, *) "    inter (opbends between molecules) :: ", inter_imprs
1056         END IF
1057         molecule_kind => molecule_kind_set(i)
1058         nval_tot2 = nval_tot2 + iimpr*SIZE(molecule_kind%molecule_list)
1059         ALLOCATE (impr_list(iimpr), STAT=stat)
1060         ALLOCATE (opbend_list(iimpr), STAT=stat)
1061         CPASSERT(stat == 0)
1062         iimpr = 0
1063         DO j = bnd_type(1, i), bnd_type(2, i)
1064            IF (j == 0) CYCLE
1065            iimpr = iimpr + 1
1066            jind = map_vars(j)
1067            first = first_list(map_atom_mol(conn_info%impr_a(jind)))
1068            impr_list(iimpr)%a = conn_info%impr_a(jind) - first + 1
1069            impr_list(iimpr)%b = conn_info%impr_b(jind) - first + 1
1070            impr_list(iimpr)%c = conn_info%impr_c(jind) - first + 1
1071            impr_list(iimpr)%d = conn_info%impr_d(jind) - first + 1
1072            ! Atom sequence for improper is A B C D in which A is central atom,
1073            ! B is deviating atom and C & D are secondairy atoms. Atom sequence for
1074            ! opbend is B D C A in which A is central atom, B is deviating. Hence
1075            ! to create an opbend out of an improper, B and D need to be interchanged.
1076            opbend_list(iimpr)%a = conn_info%impr_b(jind) - first + 1
1077            opbend_list(iimpr)%b = conn_info%impr_d(jind) - first + 1
1078            opbend_list(iimpr)%c = conn_info%impr_c(jind) - first + 1
1079            opbend_list(iimpr)%d = conn_info%impr_a(jind) - first + 1
1080            ! Set by default id_type of improper to charmm and modify when handling the forcefield
1081            impr_list(iimpr)%id_type = do_ff_charmm
1082            ! Set by default id_type of opbend to harmonic and modify when handling the forcefield
1083            opbend_list(iimpr)%id_type = do_ff_harmonic
1084            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
1085               impr_list(iimpr)%itype = conn_info%impr_type(jind)
1086            END IF
1087            !point this to the right impr_kind_type if using force field
1088            NULLIFY (impr_list(iimpr)%impr_kind)
1089            NULLIFY (opbend_list(iimpr)%opbend_kind)
1090            IF (iw > 0) THEN
1091               WRITE (iw, '(7X,A,I3,1X,A,I4,I4,I4,I4,1X,A,I4,I4,I4,I4)') &
1092                  "molecule_kind", i, "intra IMPR", &
1093                  conn_info%impr_a(jind), &
1094                  conn_info%impr_b(jind), &
1095                  conn_info%impr_c(jind), &
1096                  conn_info%impr_d(jind), &
1097                  "offset number at", &
1098                  conn_info%impr_a(jind) - first + 1, &
1099                  conn_info%impr_b(jind) - first + 1, &
1100                  conn_info%impr_c(jind) - first + 1, &
1101                  conn_info%impr_d(jind) - first + 1
1102               WRITE (iw, '(7X,A,I3,1X,A,I4,I4,I4,I4,1X,A,I4,I4,I4,I4)') &
1103                  "molecule_kind", i, "intra OPBEND", &
1104                  conn_info%impr_b(jind), &
1105                  conn_info%impr_d(jind), &
1106                  conn_info%impr_c(jind), &
1107                  conn_info%impr_a(jind), &
1108                  "offset number at", &
1109                  conn_info%impr_b(jind) - first + 1, &
1110                  conn_info%impr_d(jind) - first + 1, &
1111                  conn_info%impr_c(jind) - first + 1, &
1112                  conn_info%impr_a(jind) - first + 1
1113            END IF
1114         END DO
1115         DO j = bnd_ctype(1, i), bnd_ctype(2, i)
1116            IF (j == 0) CYCLE
1117            iimpr = iimpr + 1
1118            jind = map_cvars(j)
1119            min_index = MIN(c_var_a(jind), c_var_b(jind), c_var_c(jind), c_var_d(jind))
1120            first = first_list(map_atom_mol(min_index))
1121            impr_list(iimpr)%a = c_var_a(jind) - first + 1
1122            impr_list(iimpr)%b = c_var_b(jind) - first + 1
1123            impr_list(iimpr)%c = c_var_c(jind) - first + 1
1124            impr_list(iimpr)%d = c_var_d(jind) - first + 1
1125            opbend_list(iimpr)%a = c_var_b(jind) - first + 1
1126            opbend_list(iimpr)%b = c_var_d(jind) - first + 1
1127            opbend_list(iimpr)%c = c_var_c(jind) - first + 1
1128            opbend_list(iimpr)%d = c_var_a(jind) - first + 1
1129            ! Set by default id_type of improper to charmm and modify when handling the forcefield
1130            impr_list(iimpr)%id_type = do_ff_charmm
1131            ! Set by default id_type of opbend to harmonic and modify when handling the forcefield
1132            opbend_list(iimpr)%id_type = do_ff_harmonic
1133            IF ((topology%conn_type == do_conn_g96) .OR. (topology%conn_type == do_conn_g87)) THEN
1134               impr_list(iimpr)%itype = c_var_type(jind)
1135            END IF
1136            !point this to the right impr_kind_type and opbend_kind_type if using force field
1137            NULLIFY (impr_list(iimpr)%impr_kind)
1138            NULLIFY (opbend_list(iimpr)%opbend_kind)
1139            IF (iw > 0) THEN
1140               WRITE (iw, '(7X,A,I3,1X,A,I4,I4,I4,I4,1X,A,I4,I4,I4,I4)') &
1141                  "molecule_kind", i, "inter IMPR", &
1142                  c_var_a(jind), &
1143                  c_var_b(jind), &
1144                  c_var_c(jind), &
1145                  c_var_d(jind), &
1146                  "offset number at", &
1147                  c_var_a(jind) - first + 1, &
1148                  c_var_b(jind) - first + 1, &
1149                  c_var_c(jind) - first + 1, &
1150                  c_var_d(jind) - first + 1
1151               WRITE (iw, '(7X,A,I3,1X,A,I4,I4,I4,I4,1X,A,I4,I4,I4,I4)') &
1152                  "molecule_kind", i, "inter OPBEND", &
1153                  c_var_b(jind), &
1154                  c_var_d(jind), &
1155                  c_var_c(jind), &
1156                  c_var_a(jind), &
1157                  "offset number at", &
1158                  c_var_b(jind) - first + 1, &
1159                  c_var_d(jind) - first + 1, &
1160                  c_var_c(jind) - first + 1, &
1161                  c_var_a(jind) - first + 1
1162            END IF
1163         END DO
1164         CALL set_molecule_kind(molecule_kind=molecule_kind, &
1165                                nimpr=SIZE(impr_list), impr_list=impr_list)
1166         CALL set_molecule_kind(molecule_kind=molecule_kind, &
1167                                nopbend=SIZE(opbend_list), opbend_list=opbend_list)
1168      END DO
1169      CPASSERT(nval_tot1 == nval_tot2)
1170      DEALLOCATE (map_var_mol)
1171      DEALLOCATE (map_cvar_mol)
1172      DEALLOCATE (map_vars)
1173      DEALLOCATE (map_cvars)
1174      DEALLOCATE (bnd_type)
1175      DEALLOCATE (bnd_ctype)
1176      DEALLOCATE (c_var_a)
1177      DEALLOCATE (c_var_b)
1178      DEALLOCATE (c_var_c)
1179      DEALLOCATE (c_var_d)
1180      IF (found) THEN
1181         DEALLOCATE (c_var_type)
1182      END IF
1183      CALL timestop(handle2)
1184      !-----------------------------------------------------------------------------
1185      !-----------------------------------------------------------------------------
1186      ! Finally deallocate some stuff.
1187      !-----------------------------------------------------------------------------
1188      DEALLOCATE (first_list)
1189      DEALLOCATE (last_list)
1190      DEALLOCATE (map_atom_mol)
1191      DEALLOCATE (map_atom_type)
1192      CALL timestop(handle)
1193      CALL cp_print_key_finished_output(iw, logger, subsys_section, &
1194                                        "PRINT%TOPOLOGY_INFO/UTIL_INFO")
1195   END SUBROUTINE topology_connectivity_pack
1196
1197! **************************************************************************************************
1198!> \brief used to achieve linear scaling in the connectivity_pack
1199!> \param nmol_type ...
1200!> \param map_vars ...
1201!> \param map_var_mol ...
1202!> \param bnd_type ...
1203!> \param nvar1 ...
1204!> \par History
1205!>      Teodoro Laino
1206! **************************************************************************************************
1207   SUBROUTINE find_bnd_typ(nmol_type, map_vars, map_var_mol, bnd_type, nvar1)
1208      INTEGER, INTENT(IN)                                :: nmol_type
1209      INTEGER, DIMENSION(:), POINTER                     :: map_vars, map_var_mol
1210      INTEGER, DIMENSION(:, :), POINTER                  :: bnd_type
1211      INTEGER, INTENT(IN)                                :: nvar1
1212
1213      CHARACTER(len=*), PARAMETER :: routineN = 'find_bnd_typ', routineP = moduleN//':'//routineN
1214
1215      INTEGER                                            :: i, ibond, j
1216
1217      ALLOCATE (map_vars(nvar1))
1218      CALL sort(map_var_mol, nvar1, map_vars)
1219      ALLOCATE (bnd_type(2, nmol_type))
1220      bnd_type = 0
1221      IF (nvar1 == 0) RETURN
1222      DO j = 1, nvar1
1223         IF (map_var_mol(j) /= -1) EXIT
1224      END DO
1225      IF (j == nvar1 + 1) RETURN
1226      i = map_var_mol(j)
1227      bnd_type(1, i) = j
1228      DO ibond = j, nvar1
1229         IF (map_var_mol(ibond) /= i) THEN
1230            bnd_type(2, i) = ibond - 1
1231            i = map_var_mol(ibond)
1232            bnd_type(1, i) = ibond
1233         END IF
1234      END DO
1235      bnd_type(2, i) = nvar1
1236
1237   END SUBROUTINE find_bnd_typ
1238
1239! **************************************************************************************************
1240!> \brief   Handles the multiple unit cell option for the connectivity
1241!> \param topology ...
1242!> \param subsys_section ...
1243!> \author  Teodoro Laino [tlaino] - 06.2009
1244! **************************************************************************************************
1245   SUBROUTINE topology_conn_multiple(topology, subsys_section)
1246      TYPE(topology_parameters_type), INTENT(INOUT)      :: topology
1247      TYPE(section_vals_type), POINTER                   :: subsys_section
1248
1249      CHARACTER(len=*), PARAMETER :: routineN = 'topology_conn_multiple', &
1250         routineP = moduleN//':'//routineN
1251
1252      INTEGER                                            :: a, fac, i, ind, j, k, m, natoms_orig, &
1253                                                            nbond, nbond_c, nimpr, nonfo, nphi, &
1254                                                            ntheta, nub
1255      INTEGER, DIMENSION(:), POINTER                     :: multiple_unit_cell
1256      TYPE(connectivity_info_type), POINTER              :: conn_info
1257
1258      NULLIFY (multiple_unit_cell)
1259      CALL section_vals_val_get(subsys_section, "TOPOLOGY%MULTIPLE_UNIT_CELL", &
1260                                i_vals=multiple_unit_cell)
1261      IF (ANY(multiple_unit_cell /= 1)) THEN
1262         fac = PRODUCT(multiple_unit_cell)
1263         conn_info => topology%conn_info
1264
1265         nbond = 0
1266         IF (ASSOCIATED(conn_info%bond_a)) THEN
1267            nbond = SIZE(conn_info%bond_a)
1268            CALL reallocate(conn_info%bond_a, 1, nbond*fac)
1269            CALL reallocate(conn_info%bond_b, 1, nbond*fac)
1270         END IF
1271
1272         ntheta = 0
1273         IF (ASSOCIATED(conn_info%theta_a)) THEN
1274            ntheta = SIZE(conn_info%theta_a)
1275            CALL reallocate(conn_info%theta_a, 1, ntheta*fac)
1276            CALL reallocate(conn_info%theta_b, 1, ntheta*fac)
1277            CALL reallocate(conn_info%theta_c, 1, ntheta*fac)
1278         END IF
1279
1280         nphi = 0
1281         IF (ASSOCIATED(conn_info%phi_a)) THEN
1282            nphi = SIZE(conn_info%phi_a)
1283            CALL reallocate(conn_info%phi_a, 1, nphi*fac)
1284            CALL reallocate(conn_info%phi_b, 1, nphi*fac)
1285            CALL reallocate(conn_info%phi_c, 1, nphi*fac)
1286            CALL reallocate(conn_info%phi_d, 1, nphi*fac)
1287         END IF
1288
1289         nimpr = 0
1290         IF (ASSOCIATED(conn_info%impr_a)) THEN
1291            nimpr = SIZE(conn_info%impr_a)
1292            CALL reallocate(conn_info%impr_a, 1, nimpr*fac)
1293            CALL reallocate(conn_info%impr_b, 1, nimpr*fac)
1294            CALL reallocate(conn_info%impr_c, 1, nimpr*fac)
1295            CALL reallocate(conn_info%impr_d, 1, nimpr*fac)
1296         END IF
1297
1298         nbond_c = 0
1299         IF (ASSOCIATED(conn_info%c_bond_a)) THEN
1300            nbond_c = SIZE(conn_info%c_bond_a)
1301            CALL reallocate(conn_info%c_bond_a, 1, nbond_c*fac)
1302            CALL reallocate(conn_info%c_bond_b, 1, nbond_c*fac)
1303         END IF
1304
1305         nub = 0
1306         IF (ASSOCIATED(conn_info%ub_a)) THEN
1307            nub = SIZE(conn_info%ub_a)
1308            CALL reallocate(conn_info%ub_a, 1, nub*fac)
1309            CALL reallocate(conn_info%ub_b, 1, nub*fac)
1310            CALL reallocate(conn_info%ub_c, 1, nub*fac)
1311         END IF
1312
1313         nonfo = 0
1314         IF (ASSOCIATED(conn_info%onfo_a)) THEN
1315            nonfo = SIZE(conn_info%onfo_a)
1316            CALL reallocate(conn_info%onfo_a, 1, nonfo*fac)
1317            CALL reallocate(conn_info%onfo_b, 1, nonfo*fac)
1318         END IF
1319
1320         natoms_orig = topology%natoms/fac
1321         ind = 0
1322         DO k = 1, multiple_unit_cell(3)
1323            DO j = 1, multiple_unit_cell(2)
1324               DO i = 1, multiple_unit_cell(1)
1325                  ind = ind + 1
1326                  IF (ind == 1) CYCLE
1327                  a = (ind - 1)*natoms_orig
1328
1329                  ! Bonds
1330                  IF (nbond > 0) THEN
1331                     m = (ind - 1)*nbond
1332                     conn_info%bond_a(m + 1:m + nbond) = conn_info%bond_a(1:nbond) + a
1333                     conn_info%bond_b(m + 1:m + nbond) = conn_info%bond_b(1:nbond) + a
1334                  END IF
1335                  ! Theta
1336                  IF (ntheta > 0) THEN
1337                     m = (ind - 1)*ntheta
1338                     conn_info%theta_a(m + 1:m + ntheta) = conn_info%theta_a(1:ntheta) + a
1339                     conn_info%theta_b(m + 1:m + ntheta) = conn_info%theta_b(1:ntheta) + a
1340                     conn_info%theta_c(m + 1:m + ntheta) = conn_info%theta_c(1:ntheta) + a
1341                  END IF
1342                  ! Phi
1343                  IF (nphi > 0) THEN
1344                     m = (ind - 1)*nphi
1345                     conn_info%phi_a(m + 1:m + nphi) = conn_info%phi_a(1:nphi) + a
1346                     conn_info%phi_b(m + 1:m + nphi) = conn_info%phi_b(1:nphi) + a
1347                     conn_info%phi_c(m + 1:m + nphi) = conn_info%phi_c(1:nphi) + a
1348                     conn_info%phi_d(m + 1:m + nphi) = conn_info%phi_d(1:nphi) + a
1349                  END IF
1350                  ! Impropers
1351                  IF (nimpr > 0) THEN
1352                     m = (ind - 1)*nimpr
1353                     conn_info%impr_a(m + 1:m + nimpr) = conn_info%impr_a(1:nimpr) + a
1354                     conn_info%impr_b(m + 1:m + nimpr) = conn_info%impr_b(1:nimpr) + a
1355                     conn_info%impr_c(m + 1:m + nimpr) = conn_info%impr_c(1:nimpr) + a
1356                     conn_info%impr_d(m + 1:m + nimpr) = conn_info%impr_d(1:nimpr) + a
1357                  END IF
1358                  ! Para_res
1359                  IF (nbond_c > 0) THEN
1360                     m = (ind - 1)*nbond_c
1361                     conn_info%c_bond_a(m + 1:m + nbond_c) = conn_info%c_bond_a(1:nbond_c) + a
1362                     conn_info%c_bond_b(m + 1:m + nbond_c) = conn_info%c_bond_b(1:nbond_c) + a
1363                  END IF
1364                  ! Urey-Bradley
1365                  IF (nub > 0) THEN
1366                     m = (ind - 1)*nub
1367                     conn_info%ub_a(m + 1:m + nub) = conn_info%ub_a(1:nub) + a
1368                     conn_info%ub_b(m + 1:m + nub) = conn_info%ub_b(1:nub) + a
1369                     conn_info%ub_c(m + 1:m + nub) = conn_info%ub_c(1:nub) + a
1370                  END IF
1371                  ! ONFO
1372                  IF (nonfo > 0) THEN
1373                     m = (ind - 1)*nonfo
1374                     conn_info%onfo_a(m + 1:m + nonfo) = conn_info%onfo_a(1:nonfo) + a
1375                     conn_info%onfo_b(m + 1:m + nonfo) = conn_info%onfo_b(1:nonfo) + a
1376                  END IF
1377               END DO
1378            END DO
1379         END DO
1380      END IF
1381
1382   END SUBROUTINE topology_conn_multiple
1383
1384END MODULE topology_connectivity_util
1385