(git:374b731)
Loading...
Searching...
No Matches
qmmmx_util.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Routines used for force-mixing QM/MM calculations
10!> \par History
11!> 2.2012 created [noam]
12!> \author Noam Bernstein
13! **************************************************************************************************
18 USE cell_types, ONLY: cell_copy,&
19 cell_type,&
20 pbc
28 USE input_section_types, ONLY: &
33 USE kinds, ONLY: default_string_length,&
34 dp
42 USE qmmm_types, ONLY: qmmm_env_get
53#include "./base/base_uses.f90"
54
55 IMPLICIT NONE
56 PRIVATE
57
58 LOGICAL, PRIVATE :: debug_this_module = .false.
59 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qmmmx_util'
60
63
64CONTAINS
65
66! **************************************************************************************************
67!> \brief Apply translation to the full system in order to center the QM
68!> system into the QM box
69!> \param qmmmx_env ...
70!> \par History
71!> 08.2007 created [tlaino] - Zurich University
72!> \author Teodoro Laino
73! **************************************************************************************************
74 SUBROUTINE apply_qmmmx_translate(qmmmx_env)
75 TYPE(qmmmx_env_type), POINTER :: qmmmx_env
76
77 INTEGER :: ip
78 TYPE(cell_type), POINTER :: cell_core, cell_extended
79 TYPE(cp_subsys_type), POINTER :: subsys_core, subsys_extended
80 TYPE(particle_type), DIMENSION(:), POINTER :: particles_core, particles_extended
81
82 NULLIFY (cell_core, cell_extended)
83 NULLIFY (subsys_core, subsys_extended)
84 NULLIFY (particles_core, particles_extended)
85
86 ! want to center extended, and make core consistent with that
87 CALL apply_qmmm_translate(qmmmx_env%ext)
88
89 ! translate core fist particles
90 CALL qmmm_env_get(qmmmx_env%ext, subsys=subsys_extended)
91 CALL cp_subsys_get(subsys_extended, cell=cell_extended)
92 CALL qmmm_env_get(qmmmx_env%core, subsys=subsys_core)
93 CALL cp_subsys_get(subsys_core, cell=cell_core)
94 particles_extended => subsys_extended%particles%els
95 particles_core => subsys_core%particles%els
96 DO ip = 1, SIZE(particles_extended)
97 particles_core(ip)%r = particles_extended(ip)%r
98 END DO
99 CALL cell_copy(cell_extended, cell_core)
100
101 ! The core QM particles will be updated the regular call
102 ! to apply_qmmm_translate() from within qmmm_calc_energy_force()
103
104 END SUBROUTINE apply_qmmmx_translate
105
106! **************************************************************************************************
107!> \brief ...
108!> \param subsys ...
109!> \param qmmm_section ...
110!> \param labels_changed ...
111!> \par History
112!> 02.2012 created [noam]
113!> \author Noam Bernstein
114! **************************************************************************************************
115 SUBROUTINE update_force_mixing_labels(subsys, qmmm_section, labels_changed)
116 TYPE(cp_subsys_type), POINTER :: subsys
117 TYPE(section_vals_type), POINTER :: qmmm_section
118 LOGICAL, OPTIONAL :: labels_changed
119
120 CHARACTER(LEN=default_string_length), POINTER :: adaptive_exclude_molecules(:)
121 INTEGER :: i_rep_section, i_rep_val, ip, max_n_qm, n_new, n_rep_exclude, n_rep_section, &
122 n_rep_val, natoms, output_unit, qm_extended_seed_min_label_val
123 INTEGER, ALLOCATABLE :: new_full_labels(:), orig_full_labels(:)
124 INTEGER, POINTER :: broken_bonds(:), cur_indices(:), &
125 cur_labels(:), mm_index_entry(:), &
126 new_indices(:), new_labels(:)
127 LOGICAL :: explicit, qm_extended_seed_is_core_list
128 REAL(dp), ALLOCATABLE :: nearest_dist(:)
129 REAL(dp), POINTER :: r_buf(:), r_core(:), r_qm(:)
130 TYPE(cell_type), POINTER :: cell
131 TYPE(fist_neighbor_type), POINTER :: nlist
132 TYPE(molecule_list_type), POINTER :: molecules
133 TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
134 TYPE(mp_para_env_type), POINTER :: para_env
135 TYPE(particle_list_type), POINTER :: particles
136 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
137 TYPE(section_vals_type), POINTER :: force_mixing_section, &
138 non_adaptive_section, qm_kind_section, &
139 restart_section
140
141 output_unit = cp_logger_get_default_io_unit()
142
143 IF (debug_this_module .AND. output_unit > 0) WRITE (output_unit, *) "BOB starting update_force_mixing_labels"
144 ! get cur indices, labels
145 force_mixing_section => section_vals_get_subs_vals3(qmmm_section, "FORCE_MIXING")
146 CALL get_force_mixing_indices(force_mixing_section, cur_indices, cur_labels)
147 IF (debug_this_module .AND. output_unit > 0) WRITE (output_unit, *) "BOB got cur_indices ", SIZE(cur_indices)
148 IF (debug_this_module .AND. output_unit > 0) WRITE (output_unit, *) "BOB got cur_labels ", SIZE(cur_labels)
149
150 ! read from input
151 ![NB] breakable bonds will come from here, too
152 NULLIFY (r_core, r_qm, r_buf, adaptive_exclude_molecules, broken_bonds)
153 CALL section_vals_val_get(force_mixing_section, "R_CORE", r_vals=r_core)
154 CALL section_vals_val_get(force_mixing_section, "R_QM", r_vals=r_qm)
155 CALL section_vals_val_get(force_mixing_section, "QM_EXTENDED_SEED_IS_ONLY_CORE_LIST", &
156 l_val=qm_extended_seed_is_core_list)
157 CALL section_vals_val_get(force_mixing_section, "R_BUF", r_vals=r_buf)
158 CALL section_vals_val_get(force_mixing_section, "MAX_N_QM", i_val=max_n_qm)
159
160 CALL section_vals_val_get(force_mixing_section, "ADAPTIVE_EXCLUDE_MOLECULES", n_rep_val=n_rep_exclude)
161 IF (n_rep_exclude > 0) THEN
162 CALL section_vals_val_get(force_mixing_section, "ADAPTIVE_EXCLUDE_MOLECULES", c_vals=adaptive_exclude_molecules)
163 END IF
164 ![NB] need to read real list from input
165 ! should be 2xN_bb integer arrays, with (1,:) indices of inside atoms, and (2,:) indices of outside atoms
166 ! maybe also breakable_bond_types, with _atomic numbers_ of inside/outside atoms?
167 ! separate lists for core/buffer?
168
169 ! get particles, molecules
170 NULLIFY (particles, molecules)
171 CALL cp_subsys_get(subsys=subsys, particles=particles, molecules=molecules)
172 particle_set => particles%els
173 molecule_set => molecules%els
174
175 natoms = SIZE(particle_set)
176
177 ! initialize new indices, labels, and new_full_labels
178 NULLIFY (new_indices, new_labels)
179 CALL reallocate(new_indices, 1, SIZE(cur_indices))
180 CALL reallocate(new_labels, 1, SIZE(cur_labels))
181 new_indices = 0
182 new_labels = force_mixing_label_none
183 ALLOCATE (new_full_labels(natoms))
184 new_full_labels = force_mixing_label_none
185
186 ! neighbor list for various hysteretic distance calls
187 NULLIFY (cell)
188 CALL cp_subsys_get(subsys, cell=cell)
189 NULLIFY (nlist)
190 CALL make_neighbor_list(force_mixing_section, subsys, cell, max(r_core(2), r_qm(2), r_buf(2)), nlist)
191
192 ! create labels for core_list from QM_KIND
193 NULLIFY (mm_index_entry)
194 qm_kind_section => section_vals_get_subs_vals3(qmmm_section, "QM_KIND")
195 CALL section_vals_get(qm_kind_section, n_repetition=n_rep_section)
196 n_new = 0
197 DO i_rep_section = 1, n_rep_section
198 CALL section_vals_val_get(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section, n_rep_val=n_rep_val)
199 DO i_rep_val = 1, n_rep_val
200 CALL section_vals_val_get(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section, i_rep_val=i_rep_val, &
201 i_vals=mm_index_entry)
202 DO ip = 1, SIZE(mm_index_entry)
203 CALL add_new_label(mm_index_entry(ip), force_mixing_label_qm_core_list, n_new, new_indices, new_labels, &
204 new_full_labels, max_n_qm)
205 END DO ! ip
206 END DO ! i_rep_val
207 END DO ! i_rep_section
208
209 IF (debug_this_module .AND. output_unit > 0) THEN
210 WRITE (output_unit, *) "BOB core_list new_indices ", new_indices(1:n_new)
211 WRITE (output_unit, *) "BOB core_list new_labels ", new_labels(1:n_new)
212 END IF
213
214 ! create labels for non adaptive QM and buffer regions from *_NON_ADAPTIVE&QM_KIND sections
215 non_adaptive_section => section_vals_get_subs_vals(qmmm_section, "FORCE_MIXING%QM_NON_ADAPTIVE", &
216 can_return_null=.true.)
217 IF (ASSOCIATED(non_adaptive_section)) THEN
218 qm_kind_section => section_vals_get_subs_vals3(non_adaptive_section, "QM_KIND")
219 CALL section_vals_get(qm_kind_section, n_repetition=n_rep_section)
220 DO i_rep_section = 1, n_rep_section
221 CALL section_vals_val_get(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section, n_rep_val=n_rep_val)
222 DO i_rep_val = 1, n_rep_val
223 CALL section_vals_val_get(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section, i_rep_val=i_rep_val, &
224 i_vals=mm_index_entry)
225 DO ip = 1, SIZE(mm_index_entry)
226 CALL add_new_label(mm_index_entry(ip), force_mixing_label_qm_dynamics_list, n_new, new_indices, new_labels, &
227 new_full_labels, max_n_qm)
228 END DO ! ip
229 END DO ! i_rep_val
230 END DO ! i_rep_section
231 END IF
232 IF (debug_this_module .AND. output_unit > 0) THEN
233 WRITE (output_unit, *) "BOB core_list + non adaptive QM new_indices ", new_indices(1:n_new)
234 WRITE (output_unit, *) "BOB core_list + non adaptive QM new_labels ", new_labels(1:n_new)
235 END IF
236 non_adaptive_section => section_vals_get_subs_vals(qmmm_section, "FORCE_MIXING%BUFFER_NON_ADAPTIVE", &
237 can_return_null=.true.)
238 IF (ASSOCIATED(non_adaptive_section)) THEN
239 qm_kind_section => section_vals_get_subs_vals3(non_adaptive_section, "QM_KIND")
240 CALL section_vals_get(qm_kind_section, n_repetition=n_rep_section)
241 DO i_rep_section = 1, n_rep_section
242 CALL section_vals_val_get(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section, n_rep_val=n_rep_val)
243 DO i_rep_val = 1, n_rep_val
244 CALL section_vals_val_get(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section, i_rep_val=i_rep_val, &
245 i_vals=mm_index_entry)
246 DO ip = 1, SIZE(mm_index_entry)
247 CALL add_new_label(mm_index_entry(ip), force_mixing_label_buffer_list, n_new, new_indices, new_labels, &
248 new_full_labels, max_n_qm)
249 END DO ! ip
250 END DO ! i_rep_val
251 END DO ! i_rep_section
252 END IF
253
254 IF (debug_this_module .AND. output_unit > 0) THEN
255 WRITE (output_unit, *) "BOB core_list + non adaptive QM+buffer new_indices ", new_indices(1:n_new)
256 WRITE (output_unit, *) "BOB core_list + non adaptive QM+buffer new_labels ", new_labels(1:n_new)
257 END IF
258
259 ! allocate and initialize full atom set labels for hysteretic loops
260 ALLOCATE (nearest_dist(natoms))
261
262 ! orig_full_labels is full array (natoms) with orig labels
263 ALLOCATE (orig_full_labels(natoms))
264 orig_full_labels = force_mixing_label_none
265 orig_full_labels(cur_indices(:)) = cur_labels(:)
266
267 ! hysteretically set QM core from QM_core_list and radii, whole molecule
268 ![NB] need to replace all the whole molecule stuff with pad to breakable bonds. not quite done
269 ! (need intra molecule bond info, which isn't available for QM molecules yet)
270
271 ! add core using hysteretic selection(core_list, r_core) + unbreakable bonds
272 CALL add_layer_hysteretically( &
273 nlist, particle_set, cell, nearest_dist, &
274 orig_full_labels, new_full_labels, n_new, new_indices, new_labels, &
276 max_n_qm, adaptive_exclude_molecules, molecule_set, broken_bonds)
277 ![NB] should actually pass this back for making link sections?
278 DEALLOCATE (broken_bonds)
279
280 IF (debug_this_module .AND. output_unit > 0) THEN
281 WRITE (output_unit, *) "BOB core new_indices ", new_indices(1:n_new)
282 WRITE (output_unit, *) "BOB core new_labels ", new_labels(1:n_new)
283 END IF
284
285 ![NB] need more sophisticated QM extended, buffer rules
286
287 ! add QM using hysteretic selection (core_list, r_qm) + unbreakable bonds
288 IF (debug_this_module .AND. output_unit > 0) &
289 WRITE (output_unit, *) "BOB QM_extended_seed_is_core_list ", qm_extended_seed_is_core_list
290 IF (qm_extended_seed_is_core_list) THEN
291 qm_extended_seed_min_label_val = force_mixing_label_qm_core_list
292 ELSE ! QM region seed is all of core, not just core list + unbreakable bonds
293 qm_extended_seed_min_label_val = force_mixing_label_qm_core
294 END IF
295 CALL add_layer_hysteretically(nlist, particle_set, cell, nearest_dist, &
296 orig_full_labels, new_full_labels, n_new, new_indices, new_labels, &
297 qm_extended_seed_min_label_val, force_mixing_label_qm_core_list, &
299 max_n_qm, adaptive_exclude_molecules, molecule_set)
300
301 IF (debug_this_module .AND. output_unit > 0) THEN
302 WRITE (output_unit, *) "BOB extended new_indices ", new_indices(1:n_new)
303 WRITE (output_unit, *) "BOB extended new_labels ", new_labels(1:n_new)
304 END IF
305
306 ! add buffer using hysteretic selection (>= QM extended, r_buf) + unbreakable bonds
307 CALL add_layer_hysteretically( &
308 nlist, particle_set, cell, nearest_dist, &
309 orig_full_labels, new_full_labels, n_new, new_indices, new_labels, &
311 max_n_qm, adaptive_exclude_molecules, molecule_set, broken_bonds)
312 ![NB] should actually pass this back for making link sections?
313 DEALLOCATE (broken_bonds)
314
315 IF (debug_this_module .AND. output_unit > 0) THEN
316 WRITE (output_unit, *) "BOB buffer new_indices ", new_indices(1:n_new)
317 WRITE (output_unit, *) "BOB buffer new_labels ", new_labels(1:n_new)
318 END IF
319
320 DEALLOCATE (nearest_dist)
321
322 IF (PRESENT(labels_changed)) labels_changed = any(new_full_labels /= orig_full_labels)
323
324 DEALLOCATE (orig_full_labels)
325 DEALLOCATE (new_full_labels)
326
327 ! reduce new indices, labels to actually used size
328 CALL reallocate(new_indices, 1, n_new)
329 CALL reallocate(new_labels, 1, n_new)
330
331 ! save info in input structure
332 restart_section => section_vals_get_subs_vals(qmmm_section, "FORCE_MIXING%RESTART_INFO")
333 CALL section_vals_get(restart_section, explicit=explicit)
334 IF (explicit) CALL section_vals_remove_values(restart_section)
335 CALL section_vals_val_set(restart_section, "INDICES", i_vals_ptr=new_indices)
336 CALL section_vals_val_set(restart_section, "LABELS", i_vals_ptr=new_labels)
337
338 DEALLOCATE (cur_indices, cur_labels)
339 CALL fist_neighbor_deallocate(nlist)
340
341 ![NB] perhap be controlled by some &PRINT section?
342 CALL cp_subsys_get(subsys, para_env=para_env)
343 IF (para_env%is_source() .AND. output_unit > 0) THEN
344 WRITE (unit=output_unit, fmt='(A,A,I6,A,I5,A,I5,A,I5)') &
345 "QMMM FORCE MIXING final count (not including links): ", &
346 " N_QM core_list ", count(new_labels == force_mixing_label_qm_core_list), &
347 " N_QM core ", count(new_labels == force_mixing_label_qm_core), &
348 " N_QM extended ", count(new_labels == force_mixing_label_qm_dynamics .OR. &
350 " N_QM buffered ", count(new_labels == force_mixing_label_buffer .OR. &
351 new_labels == force_mixing_label_buffer_list)
352 END IF
353
354 END SUBROUTINE update_force_mixing_labels
355
356! **************************************************************************************************
357!> \brief ...
358!> \param ip ...
359!> \param label ...
360!> \param n_new ...
361!> \param new_indices ...
362!> \param new_labels ...
363!> \param new_full_labels ...
364!> \param max_n_qm ...
365! **************************************************************************************************
366 SUBROUTINE add_new_label(ip, label, n_new, new_indices, new_labels, new_full_labels, max_n_qm)
367 INTEGER :: ip, label, n_new
368 INTEGER, POINTER :: new_indices(:), new_labels(:)
369 INTEGER :: new_full_labels(:), max_n_qm
370
371 INTEGER :: i, old_index
372
373 IF (new_full_labels(ip) > force_mixing_label_none) THEN ! already marked, just change mark
374 old_index = -1
375 DO i = 1, n_new
376 IF (new_indices(i) == ip) THEN
377 old_index = i
378 EXIT
379 END IF
380 END DO
381 IF (old_index <= 0) &
382 CALL cp_abort(__location__, &
383 "add_new_label found atom with a label "// &
384 "already set, but not in new_indices array")
385 new_labels(old_index) = label
386 ELSE
387 n_new = n_new + 1
388 IF (n_new > max_n_qm) &
389 CALL cp_abort(__location__, &
390 "add_new_label tried to add more atoms "// &
391 "than allowed by &FORCE_MIXING&MAX_N_QM!")
392 IF (n_new > SIZE(new_indices)) CALL reallocate(new_indices, 1, n_new + 9)
393 IF (n_new > SIZE(new_labels)) CALL reallocate(new_labels, 1, n_new + 9)
394 new_indices(n_new) = ip
395 new_labels(n_new) = label
396 END IF
397 new_full_labels(ip) = label
398 END SUBROUTINE add_new_label
399
400! **************************************************************************************************
401!> \brief ...
402!> \param nlist ...
403!> \param particle_set ...
404!> \param cell ...
405!> \param nearest_dist ...
406!> \param orig_full_labels ...
407!> \param new_full_labels ...
408!> \param n_new ...
409!> \param new_indices ...
410!> \param new_labels ...
411!> \param seed_min_label_val ...
412!> \param seed_max_label_val ...
413!> \param set_label_val ...
414!> \param r_inout ...
415!> \param max_n_qm ...
416!> \param adaptive_exclude_molecules ...
417!> \param molecule_set ...
418!> \param broken_bonds ...
419! **************************************************************************************************
420 SUBROUTINE add_layer_hysteretically(nlist, particle_set, cell, nearest_dist, &
421 orig_full_labels, new_full_labels, n_new, new_indices, new_labels, &
422 seed_min_label_val, seed_max_label_val, set_label_val, r_inout, max_n_qm, &
423 adaptive_exclude_molecules, molecule_set, broken_bonds)
424 TYPE(fist_neighbor_type), POINTER :: nlist
425 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
426 TYPE(cell_type), POINTER :: cell
427 REAL(dp) :: nearest_dist(:)
428 INTEGER :: orig_full_labels(:), new_full_labels(:), &
429 n_new
430 INTEGER, POINTER :: new_indices(:), new_labels(:)
431 INTEGER :: seed_min_label_val, seed_max_label_val, &
432 set_label_val
433 REAL(dp) :: r_inout(2)
434 INTEGER :: max_n_qm
435 CHARACTER(len=*), POINTER :: adaptive_exclude_molecules(:)
436 TYPE(molecule_type), DIMENSION(:), OPTIONAL, &
437 POINTER :: molecule_set
438 INTEGER, OPTIONAL, POINTER :: broken_bonds(:)
439
440 INTEGER :: i_ind, im, im_exclude, ip, ipair, &
441 ipairkind, j_ind, output_unit
442 LOGICAL :: adaptive_exclude, i_in_new_seed, i_outside_new_seed, j_in_new_seed, &
443 j_outside_new_seed, molec_in_inner, molec_in_outer
444 REAL(dp) :: r_ij(3), r_ij_mag
445
446 output_unit = cp_logger_get_default_unit_nr()
447
448 IF (debug_this_module .AND. output_unit > 0) WRITE (output_unit, *) "BOB adding hysteretically seed ", &
449 seed_min_label_val, seed_max_label_val, " set ", set_label_val, " r ", r_inout
450 ! calculate nearest dist from each atom outside of new seed to nearest atom inside of new seed
451 nearest_dist = huge(1.0_dp)
452 ! loop over pairs of all kinds in random order
453 DO ipairkind = 1, SIZE(nlist%neighbor_kind_pairs)
454 DO ipair = 1, nlist%neighbor_kind_pairs(ipairkind)%npairs
455
456 i_ind = nlist%neighbor_kind_pairs(ipairkind)%list(1, ipair)
457 j_ind = nlist%neighbor_kind_pairs(ipairkind)%list(2, ipair)
458
459 i_in_new_seed = (new_full_labels(i_ind) >= seed_min_label_val .AND. new_full_labels(i_ind) <= seed_max_label_val)
460 i_outside_new_seed = (new_full_labels(i_ind) < seed_min_label_val)
461 j_in_new_seed = (new_full_labels(j_ind) >= seed_min_label_val .AND. new_full_labels(j_ind) <= seed_max_label_val)
462 j_outside_new_seed = (new_full_labels(j_ind) < seed_min_label_val)
463
464 IF ((i_in_new_seed .AND. j_outside_new_seed) .OR. (j_in_new_seed .AND. i_outside_new_seed)) THEN
465 r_ij = pbc(particle_set(i_ind)%r - particle_set(j_ind)%r, cell)
466 r_ij_mag = sqrt(sum(r_ij**2))
467 IF (i_in_new_seed .AND. j_outside_new_seed .AND. (r_ij_mag < nearest_dist(j_ind))) THEN
468 nearest_dist(j_ind) = r_ij_mag
469 END IF
470 IF (j_in_new_seed .AND. i_outside_new_seed .AND. (r_ij_mag < nearest_dist(i_ind))) THEN
471 nearest_dist(i_ind) = r_ij_mag
472 END IF
473 END IF
474
475 END DO
476 END DO
477
478 ![NB] this is whole molecule. Should be replaced with labeling of individual atoms +
479 ! pad_to_breakable_bonds (below), but QM molecule bond information isn't available yet
480 DO im = 1, SIZE(molecule_set)
481 ! molecule_set(im)%first_atom,molecule_set(im)%last_atom
482 IF (ASSOCIATED(adaptive_exclude_molecules)) THEN
483 adaptive_exclude = .false.
484 DO im_exclude = 1, SIZE(adaptive_exclude_molecules)
485 IF (trim(molecule_set(im)%molecule_kind%name) == trim(adaptive_exclude_molecules(im_exclude)) .OR. &
486 trim(molecule_set(im)%molecule_kind%name) == '_QM_'//trim(adaptive_exclude_molecules(im_exclude))) &
487 adaptive_exclude = .true.
488 END DO
489 IF (adaptive_exclude) cycle
490 END IF
491 molec_in_inner = any(nearest_dist(molecule_set(im)%first_atom:molecule_set(im)%last_atom) <= r_inout(1))
492 molec_in_outer = any(nearest_dist(molecule_set(im)%first_atom:molecule_set(im)%last_atom) <= r_inout(2))
493 IF (molec_in_inner) THEN
494 DO ip = molecule_set(im)%first_atom, molecule_set(im)%last_atom
495 ! labels are being rebuild from scratch, so never overwrite new label that's higher level
496 IF (new_full_labels(ip) < set_label_val) &
497 CALL add_new_label(ip, set_label_val, n_new, new_indices, new_labels, new_full_labels, max_n_qm)
498 END DO
499 ELSE IF (molec_in_outer) THEN
500 IF (any(orig_full_labels(molecule_set(im)%first_atom:molecule_set(im)%last_atom) >= set_label_val)) THEN
501 DO ip = molecule_set(im)%first_atom, molecule_set(im)%last_atom
502 ! labels are being rebuild from scratch, so never overwrite new label that's higher level
503 IF (new_full_labels(ip) < set_label_val) &
504 CALL add_new_label(ip, set_label_val, n_new, new_indices, new_labels, new_full_labels, max_n_qm)
505 END DO
506 END IF
507 END IF
508 END DO
509 IF (PRESENT(broken_bonds)) CALL reallocate(broken_bonds, 1, 0)
510
511 END SUBROUTINE add_layer_hysteretically
512
513! **************************************************************************************************
514!> \brief ...
515!> \param force_mixing_section ...
516!> \param subsys ...
517!> \param cell ...
518!> \param r_max ...
519!> \param nlist ...
520! **************************************************************************************************
521 SUBROUTINE make_neighbor_list(force_mixing_section, subsys, cell, r_max, nlist)
522 TYPE(section_vals_type), POINTER :: force_mixing_section
523 TYPE(cp_subsys_type), POINTER :: subsys
524 TYPE(cell_type), POINTER :: cell
525 REAL(dp) :: r_max
526 TYPE(fist_neighbor_type), POINTER :: nlist
527
528 CHARACTER(LEN=default_string_length) :: kind_name
529 CHARACTER(LEN=default_string_length), POINTER :: kind_name_a(:)
530 INTEGER :: ik
531 LOGICAL :: skip_kind
532 REAL(dp), ALLOCATABLE :: r_max_a(:, :), r_minsq_a(:, :)
533 TYPE(atomic_kind_type), POINTER :: atomic_kind
534
535 ALLOCATE (r_max_a(SIZE(subsys%atomic_kinds%els), SIZE(subsys%atomic_kinds%els)))
536 ALLOCATE (r_minsq_a(SIZE(subsys%atomic_kinds%els), SIZE(subsys%atomic_kinds%els)))
537 r_max_a = r_max
538 r_minsq_a = epsilon(1.0_dp)
539
540 ! save kind names
541 ALLOCATE (kind_name_a(SIZE(subsys%atomic_kinds%els)))
542 DO ik = 1, SIZE(subsys%atomic_kinds%els)
543 atomic_kind => subsys%atomic_kinds%els(ik)
544 CALL get_atomic_kind(atomic_kind=atomic_kind, name=kind_name)
545 kind_name_a(ik) = kind_name
546 END DO
547
548 ! overwrite kind names so that none are QM, and so excluding QM-QM interactions
549 ! (which is not what we want) will not happen
550 DO ik = 1, SIZE(subsys%atomic_kinds%els)
551 atomic_kind => subsys%atomic_kinds%els(ik)
552 CALL get_atomic_kind(atomic_kind=atomic_kind, name=kind_name)
553 ! when atom is QM atom, kind_name is replaced with original
554 ! mm kind name, and return status is logical .TRUE.
555 skip_kind = qmmm_ff_precond_only_qm(kind_name)
556 CALL set_atomic_kind(atomic_kind=atomic_kind, name=kind_name)
557 END DO
558
559 NULLIFY (nlist)
560 CALL build_fist_neighbor_lists(subsys%atomic_kinds%els, subsys%particles%els, &
561 cell=cell, r_max=r_max_a, r_minsq=r_minsq_a, &
562 ei_scale14=1.0_dp, vdw_scale14=1.0_dp, nonbonded=nlist, &
563 para_env=subsys%para_env, build_from_scratch=.true., geo_check=.false., &
564 mm_section=force_mixing_section)
565
566 DEALLOCATE (r_max_a, r_minsq_a)
567
568 ! restore kind names
569 DO ik = 1, SIZE(subsys%atomic_kinds%els)
570 CALL set_atomic_kind(atomic_kind=atomic_kind, name=kind_name_a(ik))
571 END DO
572 DEALLOCATE (kind_name_a)
573
574 END SUBROUTINE make_neighbor_list
575
576! **************************************************************************************************
577!> \brief ...
578!> \param subsys ...
579!> \param qmmm_section ...
580!> \param qmmm_core_section ...
581!> \param qmmm_extended_section ...
582!> \par History
583!> 02.2012 created [noam]
584!> \author Noam Bernstein
585! **************************************************************************************************
586 SUBROUTINE setup_force_mixing_qmmm_sections(subsys, qmmm_section, qmmm_core_section, qmmm_extended_section)
587 TYPE(cp_subsys_type), POINTER :: subsys
588 TYPE(section_vals_type), POINTER :: qmmm_section, qmmm_core_section, &
589 qmmm_extended_section
590
591 CHARACTER(len=default_string_length), POINTER :: elem_mapping(:, :), elem_mapping_entry(:)
592 INTEGER :: delta_charge, i_rep_section_core, i_rep_section_extended, i_rep_val_core, &
593 i_rep_val_extended, ielem, ip, n_elements, output_unit
594 INTEGER, POINTER :: cur_indices(:), cur_labels(:)
595 LOGICAL :: mapped, new_element_core, &
596 new_element_extended
597 TYPE(particle_type), DIMENSION(:), POINTER :: particles
598 TYPE(section_vals_type), POINTER :: buffer_non_adaptive_section, &
599 dup_link_section, &
600 force_mixing_section, link_section, &
601 qm_kind_section
602
603 NULLIFY (qmmm_core_section, qmmm_extended_section)
604 output_unit = cp_logger_get_default_unit_nr()
605
606 ! create new qmmm sections for core and extended
607 CALL section_vals_duplicate(qmmm_section, qmmm_core_section)
608 CALL section_vals_duplicate(qmmm_section, qmmm_extended_section)
609
610 ! remove LINKs (specified by user for core) from extended
611 link_section => section_vals_get_subs_vals(qmmm_extended_section, "LINK", can_return_null=.true.)
612 IF (ASSOCIATED(link_section)) THEN
613 CALL section_vals_remove_values(link_section)
614 END IF
615 ! for LINKs to be added to extended
616 buffer_non_adaptive_section => section_vals_get_subs_vals(qmmm_extended_section, "FORCE_MIXING%BUFFER_NON_ADAPTIVE", &
617 can_return_null=.true.)
618 link_section => section_vals_get_subs_vals(buffer_non_adaptive_section, "LINK", can_return_null=.true.)
619 IF (ASSOCIATED(link_section)) THEN
620 NULLIFY (dup_link_section)
621 CALL section_vals_duplicate(link_section, dup_link_section)
622 CALL section_vals_set_subs_vals(qmmm_extended_section, "LINK", dup_link_section)
623 CALL section_vals_release(dup_link_section)
624 END IF
625
626 IF (debug_this_module .AND. output_unit > 0) THEN
627 link_section => section_vals_get_subs_vals(qmmm_core_section, "LINK", can_return_null=.true.)
628 WRITE (output_unit, *) "core section has LINKs ", ASSOCIATED(link_section)
629 CALL section_vals_write(link_section, unit_nr=6)
630 link_section => section_vals_get_subs_vals(qmmm_extended_section, "LINK", can_return_null=.true.)
631 WRITE (output_unit, *) "extended section has LINKs ", ASSOCIATED(link_section)
632 CALL section_vals_write(link_section, unit_nr=6)
633 END IF
634
635 force_mixing_section => section_vals_get_subs_vals(qmmm_section, "FORCE_MIXING")
636
637 ! get QM_KIND_ELEMENT_MAPPING
638 CALL section_vals_val_get(force_mixing_section, "QM_KIND_ELEMENT_MAPPING", n_rep_val=n_elements)
639 ALLOCATE (elem_mapping(2, n_elements))
640 DO ielem = 1, n_elements
641 CALL section_vals_val_get(force_mixing_section, "QM_KIND_ELEMENT_MAPPING", i_rep_val=ielem, c_vals=elem_mapping_entry)
642 elem_mapping(1:2, ielem) = elem_mapping_entry(1:2)
643 END DO
644
645 ! get CUR_INDICES, CUR_LABELS
646 CALL get_force_mixing_indices(force_mixing_section, cur_indices, cur_labels)
647 IF (SIZE(cur_indices) <= 0) &
648 cpabort("cur_indices is empty, found no QM atoms")
649
650 IF (debug_this_module .AND. output_unit > 0) THEN
651 WRITE (output_unit, *) "cur_indices ", cur_indices
652 WRITE (output_unit, *) "cur_labels ", cur_labels
653 END IF
654
655 ! loop through elements and atoms, and set up new QM_KIND sections
656 particles => subsys%particles%els
657
658 DO ip = 1, SIZE(cur_indices)
659 IF (cur_labels(ip) > force_mixing_label_none .AND. cur_labels(ip) < force_mixing_label_qm_core_list .AND. &
660 cur_labels(ip) /= force_mixing_label_termination) THEN
661 mapped = .false.
662 DO ielem = 1, n_elements
663 IF (trim(particles(cur_indices(ip))%atomic_kind%element_symbol) == trim(elem_mapping(1, ielem))) THEN
664 mapped = .true.
665 EXIT
666 END IF
667 END DO
668 IF (.NOT. mapped) &
669 CALL cp_abort(__location__, &
670 "Force-mixing failed to find QM_KIND mapping for atom of type "// &
671 trim(particles(cur_indices(ip))%atomic_kind%element_symbol)// &
672 "! ")
673 END IF
674 END DO
675
676 ! pre-existing QM_KIND section specifies list of core atom
677 qm_kind_section => section_vals_get_subs_vals3(qmmm_section, "QM_KIND")
678 CALL section_vals_get(qm_kind_section, n_repetition=i_rep_section_core)
679 IF (i_rep_section_core <= 0) &
680 CALL cp_abort(__location__, &
681 "Force-mixing QM didn't find any QM_KIND sections, "// &
682 "so no core specified!")
683 i_rep_section_extended = i_rep_section_core
684 DO ielem = 1, n_elements
685 new_element_core = .true.
686 new_element_extended = .true.
687 DO ip = 1, SIZE(cur_indices) ! particles with label
688 IF (trim(particles(cur_indices(ip))%atomic_kind%element_symbol) /= trim(elem_mapping(1, ielem))) cycle
689 ! extended
690 ! if current particle is some sort of QM atom, and not in core list
691 ! (those the user gave explicit QM_KIND sections for), and not a
692 ! termination atom, need to make a QM_KIND section for it
693 IF (cur_labels(ip) > force_mixing_label_none .AND. &
694 cur_labels(ip) /= force_mixing_label_qm_core_list .AND. &
695 cur_labels(ip) /= force_mixing_label_termination) THEN
696 qm_kind_section => section_vals_get_subs_vals3(qmmm_extended_section, "QM_KIND")
697 IF (new_element_extended) THEN ! add new QM_KIND section for this element
698 i_rep_section_extended = i_rep_section_extended + 1
699 CALL section_vals_add_values(qm_kind_section)
700 CALL section_vals_val_set(qm_kind_section, "_SECTION_PARAMETERS_", i_rep_section=i_rep_section_extended, &
701 c_val=elem_mapping(2, ielem))
702 i_rep_val_extended = 0
703 new_element_extended = .false.
704 END IF
705 i_rep_val_extended = i_rep_val_extended + 1
706 CALL section_vals_val_set(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section_extended, &
707 i_rep_val=i_rep_val_extended, i_val=cur_indices(ip))
708 END IF ! is a non-termination QM atom
709
710 ! core
711 ! if current particle is a core QM atom, and not in core list (those the user
712 ! gave explicit QM_KIND sections for, need to make a QM_KIND section for it
713 IF (cur_labels(ip) == force_mixing_label_qm_core) THEN
714 qm_kind_section => section_vals_get_subs_vals3(qmmm_core_section, "QM_KIND")
715 IF (new_element_core) THEN ! add new QM_KIND section for this element
716 i_rep_section_core = i_rep_section_core + 1
717 CALL section_vals_add_values(qm_kind_section)
718 CALL section_vals_val_set(qm_kind_section, "_SECTION_PARAMETERS_", i_rep_section=i_rep_section_core, &
719 c_val=elem_mapping(2, ielem))
720 i_rep_val_core = 0
721 new_element_core = .false.
722 END IF
723 i_rep_val_core = i_rep_val_core + 1
724 CALL section_vals_val_set(qm_kind_section, "MM_INDEX", i_rep_section=i_rep_section_core, &
725 i_rep_val=i_rep_val_core, i_val=cur_indices(ip))
726 END IF ! is a non-termination QM atom
727
728 END DO ! atom index ip
729 END DO ! element index ielem
730
731 CALL section_vals_val_get(force_mixing_section, "EXTENDED_DELTA_CHARGE", i_val=delta_charge)
732 CALL section_vals_val_set(qmmm_extended_section, "DELTA_CHARGE", i_val=delta_charge)
733
734 ![NB] check
735 DEALLOCATE (elem_mapping, cur_indices, cur_labels)
736
737 IF (debug_this_module .AND. output_unit > 0) THEN
738 WRITE (output_unit, *) "qmmm_core_section"
739 CALL section_vals_write(qmmm_core_section, unit_nr=6)
740 WRITE (output_unit, *) "qmmm_extended_section"
741 CALL section_vals_write(qmmm_extended_section, unit_nr=6)
742 END IF
743
745
746! **************************************************************************************************
747!> \brief ...
748!> \param force_mixing_section ...
749!> \param indices ...
750!> \param labels ...
751! **************************************************************************************************
752 SUBROUTINE get_force_mixing_indices(force_mixing_section, indices, labels)
753 TYPE(section_vals_type), POINTER :: force_mixing_section
754 INTEGER, POINTER :: indices(:), labels(:)
755
756 INTEGER :: i_rep_val, n_indices, n_labels, n_reps
757 INTEGER, POINTER :: indices_entry(:), labels_entry(:)
758 LOGICAL :: explicit
759 TYPE(section_vals_type), POINTER :: restart_section
760
761 NULLIFY (indices, labels)
762 restart_section => section_vals_get_subs_vals(force_mixing_section, "RESTART_INFO")
763 CALL section_vals_get(restart_section, explicit=explicit)
764 IF (.NOT. explicit) THEN ! no old indices, labels, return empty arrays
765 ALLOCATE (indices(0))
766 ALLOCATE (labels(0))
767 RETURN
768 END IF
769
770 ![NB] maybe switch to reallocatable array
771 CALL section_vals_val_get(restart_section, "INDICES", n_rep_val=n_reps)
772 n_indices = 0
773 DO i_rep_val = 1, n_reps
774 CALL section_vals_val_get(restart_section, "INDICES", &
775 i_rep_val=i_rep_val, i_vals=indices_entry)
776 n_indices = n_indices + SIZE(indices_entry)
777 END DO
778 ALLOCATE (indices(n_indices))
779 n_indices = 0
780 DO i_rep_val = 1, n_reps
781 CALL section_vals_val_get(restart_section, "INDICES", &
782 i_rep_val=i_rep_val, i_vals=indices_entry)
783 indices(n_indices + 1:n_indices + SIZE(indices_entry)) = indices_entry
784 n_indices = n_indices + SIZE(indices_entry)
785 END DO
786
787 CALL section_vals_val_get(restart_section, "LABELS", n_rep_val=n_reps)
788 n_labels = 0
789 DO i_rep_val = 1, n_reps
790 CALL section_vals_val_get(restart_section, "LABELS", &
791 i_rep_val=i_rep_val, i_vals=labels_entry)
792 n_labels = n_labels + SIZE(labels_entry)
793 END DO
794 ALLOCATE (labels(n_labels))
795 n_labels = 0
796 DO i_rep_val = 1, n_reps
797 CALL section_vals_val_get(restart_section, "LABELS", &
798 i_rep_val=i_rep_val, i_vals=labels_entry)
799 labels(n_labels + 1:n_labels + SIZE(labels_entry)) = labels_entry
800 n_labels = n_labels + SIZE(labels_entry)
801 END DO
802
803 IF (n_indices /= n_labels) &
804 cpabort("got unequal numbers of force_mixing indices and labels!")
805 END SUBROUTINE get_force_mixing_indices
806
807END MODULE qmmmx_util
Define the atomic kind types and their sub types.
subroutine, public set_atomic_kind(atomic_kind, element_symbol, name, mass, kind_number, natom, atom_list, fist_potential, shell, shell_active, damping)
Set the components of an atomic kind data set.
subroutine, public get_atomic_kind(atomic_kind, fist_potential, element_symbol, name, mass, kind_number, natom, atom_list, rcov, rvdw, z, qeff, apol, cpol, mm_radius, shell, shell_active, damping)
Get attributes of an atomic kind.
Handles all functions related to the CELL.
Definition cell_types.F:15
subroutine, public cell_copy(cell_in, cell_out, tag)
Copy cell variable.
Definition cell_types.F:126
various routines to log and control the output. The idea is that decisions about where to log should ...
recursive integer function, public cp_logger_get_default_unit_nr(logger, local, skip_not_ionode)
asks the default unit number of the given logger. try to use cp_logger_get_unit_nr
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
types that represent a subsys, i.e. a part of the system
subroutine, public cp_subsys_get(subsys, ref_count, atomic_kinds, atomic_kind_set, particles, particle_set, local_particles, molecules, molecule_set, molecule_kinds, molecule_kind_set, local_molecules, para_env, colvar_p, shell_particles, core_particles, gci, multipoles, natom, nparticle, ncore, nshell, nkind, atprop, virial, results, cell)
returns information about various attributes of the given subsys
Define the neighbor list data types and the corresponding functionality.
subroutine, public fist_neighbor_deallocate(fist_neighbor)
...
Generate the atomic neighbor lists for FIST.
subroutine, public build_fist_neighbor_lists(atomic_kind_set, particle_set, local_particles, cell, r_max, r_minsq, ei_scale14, vdw_scale14, nonbonded, para_env, build_from_scratch, geo_check, mm_section, full_nl, exclusions)
...
objects that represent the structure of input sections and the data contained in an input section
subroutine, public section_vals_val_set(section_vals, keyword_name, i_rep_section, i_rep_val, val, l_val, i_val, r_val, c_val, l_vals_ptr, i_vals_ptr, r_vals_ptr, c_vals_ptr)
sets the requested value
subroutine, public section_vals_remove_values(section_vals)
removes the values of a repetition of the section
recursive type(section_vals_type) function, pointer, public section_vals_get_subs_vals(section_vals, subsection_name, i_rep_section, can_return_null)
returns the values of the requested subsection
recursive subroutine, public section_vals_write(section_vals, unit_nr, hide_root, hide_defaults)
writes the values in the given section in a way that is suitable to the automatic parsing
subroutine, public section_vals_get(section_vals, ref_count, n_repetition, n_subs_vals_rep, section, explicit)
returns various attributes about the section_vals
type(section_vals_type) function, pointer, public section_vals_get_subs_vals3(section_vals, subsection_name, i_rep_section)
returns the values of the n-th non default subsection (null if no such section exists (not so many no...
subroutine, public section_vals_set_subs_vals(section_vals, subsection_name, new_section_vals, i_rep_section)
replaces of the requested subsection with the one given
subroutine, public section_vals_duplicate(section_vals_in, section_vals_out, i_rep_start, i_rep_end)
creates a deep copy from section_vals_in to section_vals_out
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
subroutine, public section_vals_add_values(section_vals)
adds the place to store the values of a repetition of the section
recursive subroutine, public section_vals_release(section_vals)
releases the given object
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
Utility routines for the memory handling.
Interface to the message passing library MPI.
represent a simple array based list of the given type
Define the data structure for the molecule information.
represent a simple array based list of the given type
Define the data structure for the particle information.
logical function, public qmmm_ff_precond_only_qm(id1, id2, id3, id4, is_link)
This function handles the atom names and modifies the "_QM_" prefix, in order to find the parameters ...
integer, parameter, public force_mixing_label_qm_core
integer, parameter, public force_mixing_label_buffer
integer, parameter, public force_mixing_label_none
integer, parameter, public force_mixing_label_qm_core_list
integer, parameter, public force_mixing_label_qm_dynamics_list
integer, parameter, public force_mixing_label_termination
integer, parameter, public force_mixing_label_buffer_list
integer, parameter, public force_mixing_label_qm_dynamics
Basic container type for QM/MM.
Definition qmmm_types.F:12
subroutine, public qmmm_env_get(qmmm_env, subsys, potential_energy, kinetic_energy)
...
Definition qmmm_types.F:50
subroutine, public apply_qmmm_translate(qmmm_env)
Apply translation to the full system in order to center the QM system into the QM box.
Definition qmmm_util.F:373
Basic container type for QM/MM with force mixing.
Definition qmmmx_types.F:12
Routines used for force-mixing QM/MM calculations.
Definition qmmmx_util.F:14
subroutine, public apply_qmmmx_translate(qmmmx_env)
Apply translation to the full system in order to center the QM system into the QM box.
Definition qmmmx_util.F:75
subroutine, public setup_force_mixing_qmmm_sections(subsys, qmmm_section, qmmm_core_section, qmmm_extended_section)
...
Definition qmmmx_util.F:587
subroutine, public update_force_mixing_labels(subsys, qmmm_section, labels_changed)
...
Definition qmmmx_util.F:116
Provides all information about an atomic kind.
Type defining parameters related to the simulation cell.
Definition cell_types.F:55
represents a system: atoms, molecules, their pos,vel,...
stores all the informations relevant to an mpi environment