38#include "./base/base_uses.f90"
43 LOGICAL,
PRIVATE,
PARAMETER :: debug_this_module = .false.
44 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'qmmm_util'
66 LOGICAL :: do_qmmm_force_mixing, explicit
75 SELECT CASE (iwall_type)
77 IF (do_qmmm_force_mixing)
THEN
78 CALL cp_warn(__location__, &
79 "Quadratic walls for QM/MM are not implemented (or useful), when "// &
80 "force mixing is active. Skipping!")
82 CALL apply_qmmm_walls_quadratic(qmmm_env, walls_section)
102 INTEGER :: ip, iwall_type, qm_index
103 INTEGER,
DIMENSION(:),
POINTER :: qm_atom_index
104 LOGICAL :: explicit, is_x(2), is_y(2), is_z(2)
105 REAL(kind=
dp),
DIMENSION(3) :: coord, qm_cell_diag, skin
106 REAL(kind=
dp),
DIMENSION(:),
POINTER ::
list
107 TYPE(
cell_type),
POINTER :: mm_cell, qm_cell
112 NULLIFY (subsys_mm, subsys_qm, qm_atom_index, particles_mm, qm_cell, mm_cell, &
132 CALL cp_warn(__location__, &
133 "Reflective walls for QM/MM are not implemented (or useful) when "// &
134 "force mixing is active. Skipping!")
139 cpassert(
ASSOCIATED(force_env%qmmm_env))
141 CALL fist_env_get(force_env%qmmm_env%fist_env, cell=mm_cell, subsys=subsys_mm)
142 CALL get_qs_env(force_env%qmmm_env%qs_env, cell=qm_cell, cp_subsys=subsys_qm)
143 qm_atom_index => force_env%qmmm_env%qm%qm_atom_index
144 cpassert(
ASSOCIATED(qm_atom_index))
146 qm_cell_diag = [qm_cell%hmat(1, 1), &
147 qm_cell%hmat(2, 2), &
149 particles_mm => subsys_mm%particles%els
150 DO ip = 1,
SIZE(qm_atom_index)
151 qm_index = qm_atom_index(ip)
152 coord = particles_mm(qm_index)%r
153 IF (any(coord < skin) .OR. any(coord > (qm_cell_diag - skin)))
THEN
157 is_x(1) = (coord(1) < skin(1))
158 is_x(2) = (coord(1) > (qm_cell_diag(1) - skin(1)))
159 is_y(1) = (coord(2) < skin(2))
160 is_y(2) = (coord(2) > (qm_cell_diag(2) - skin(2)))
161 is_z(1) = (coord(3) < skin(3))
162 is_z(2) = (coord(3) > (qm_cell_diag(3) - skin(3)))
166 particles_mm(qm_index)%v(1) = abs(particles_mm(qm_index)%v(1))
167 ELSE IF (is_x(2))
THEN
168 particles_mm(qm_index)%v(1) = -abs(particles_mm(qm_index)%v(1))
174 particles_mm(qm_index)%v(2) = abs(particles_mm(qm_index)%v(2))
175 ELSE IF (is_y(2))
THEN
176 particles_mm(qm_index)%v(2) = -abs(particles_mm(qm_index)%v(2))
182 particles_mm(qm_index)%v(3) = abs(particles_mm(qm_index)%v(3))
183 ELSE IF (is_z(2))
THEN
184 particles_mm(qm_index)%v(3) = -abs(particles_mm(qm_index)%v(3))
190 CALL cp_warn(__location__, &
191 "One or few QM atoms are within the SKIN of the quantum box. Check your run "// &
192 "and you may possibly consider: the activation of the QMMM WALLS "// &
193 "around the QM box, switching ON the centering of the QM box or increase "// &
194 "the size of the QM cell. CP2K CONTINUE but results could be meaningless. ")
210 SUBROUTINE apply_qmmm_walls_quadratic(qmmm_env, walls_section)
214 INTEGER :: ip, qm_index
215 INTEGER,
DIMENSION(:),
POINTER :: qm_atom_index
216 LOGICAL :: is_x(2), is_y(2), is_z(2)
217 REAL(kind=
dp) :: k, wallenergy, wallforce
218 REAL(kind=
dp),
DIMENSION(3) :: coord, qm_cell_diag, skin
219 REAL(kind=
dp),
DIMENSION(:),
POINTER ::
list
220 TYPE(
cell_type),
POINTER :: mm_cell, qm_cell
228 cpassert(
ASSOCIATED(qmmm_env))
230 CALL fist_env_get(qmmm_env%fist_env, cell=mm_cell, subsys=subsys_mm)
231 CALL get_qs_env(qmmm_env%qs_env, cell=qm_cell, cp_subsys=subsys_qm)
233 qm_atom_index => qmmm_env%qm%qm_atom_index
234 cpassert(
ASSOCIATED(qm_atom_index))
238 qm_cell_diag = [qm_cell%hmat(1, 1), &
239 qm_cell%hmat(2, 2), &
241 particles_mm => subsys_mm%particles%els
243 DO ip = 1,
SIZE(qm_atom_index)
244 qm_index = qm_atom_index(ip)
245 coord = particles_mm(qm_index)%r
246 IF (any(coord < skin) .OR. any(coord > (qm_cell_diag - skin)))
THEN
247 is_x(1) = (coord(1) < skin(1))
248 is_x(2) = (coord(1) > (qm_cell_diag(1) - skin(1)))
249 is_y(1) = (coord(2) < skin(2))
250 is_y(2) = (coord(2) > (qm_cell_diag(2) - skin(2)))
251 is_z(1) = (coord(3) < skin(3))
252 is_z(2) = (coord(3) > (qm_cell_diag(3) - skin(3)))
254 wallforce = 2.0_dp*k*(skin(1) - coord(1))
255 particles_mm(qm_index)%f(1) = particles_mm(qm_index)%f(1) + &
257 wallenergy = wallenergy + wallforce*(skin(1) - coord(1))*0.5_dp
260 wallforce = 2.0_dp*k*((qm_cell_diag(1) - skin(1)) - coord(1))
261 particles_mm(qm_index)%f(1) = particles_mm(qm_index)%f(1) + &
263 wallenergy = wallenergy + wallforce*((qm_cell_diag(1) - skin(1)) - &
267 wallforce = 2.0_dp*k*(skin(2) - coord(2))
268 particles_mm(qm_index)%f(2) = particles_mm(qm_index)%f(2) + &
270 wallenergy = wallenergy + wallforce*(skin(2) - coord(2))*0.5_dp
273 wallforce = 2.0_dp*k*((qm_cell_diag(2) - skin(2)) - coord(2))
274 particles_mm(qm_index)%f(2) = particles_mm(qm_index)%f(2) + &
276 wallenergy = wallenergy + wallforce*((qm_cell_diag(2) - skin(2)) - &
280 wallforce = 2.0_dp*k*(skin(3) - coord(3))
281 particles_mm(qm_index)%f(3) = particles_mm(qm_index)%f(3) + &
283 wallenergy = wallenergy + wallforce*(skin(3) - coord(3))*0.5_dp
286 wallforce = 2.0_dp*k*((qm_cell_diag(3) - skin(3)) - coord(3))
287 particles_mm(qm_index)%f(3) = particles_mm(qm_index)%f(3) + &
289 wallenergy = wallenergy + wallforce*((qm_cell_diag(3) - skin(3)) - &
295 CALL get_qs_env(qs_env=qmmm_env%qs_env, energy=energy)
296 energy%total = energy%total + wallenergy
298 END SUBROUTINE apply_qmmm_walls_quadratic
312 INTEGER,
DIMENSION(:),
OPTIONAL,
POINTER :: qm_atom_index
313 REAL(
dp),
ALLOCATABLE :: saved_pos(:, :)
318 ALLOCATE (saved_pos(3, subsys_mm%particles%n_els))
319 DO ip = 1, subsys_mm%particles%n_els
320 saved_pos(1:3, ip) = subsys_mm%particles%els(ip)%r(1:3)
321 r_lat = matmul(mm_cell%h_inv, subsys_mm%particles%els(ip)%r)
323 IF (mm_cell%perd(i_dim) /= 1)
THEN
324 r_lat(i_dim) = 0.0_dp
327 subsys_mm%particles%els(ip)%r = subsys_mm%particles%els(ip)%r - matmul(mm_cell%hmat, floor(r_lat))
330 IF (
PRESENT(subsys_qm) .AND.
PRESENT(qm_atom_index))
THEN
331 DO ip = 1,
SIZE(qm_atom_index)
332 subsys_qm%particles%els(ip)%r = subsys_mm%particles%els(qm_atom_index(ip))%r
347 INTEGER,
DIMENSION(:),
OPTIONAL,
POINTER :: qm_atom_index
348 REAL(
dp),
ALLOCATABLE :: saved_pos(:, :)
352 DO ip = 1, subsys_mm%particles%n_els
353 subsys_mm%particles%els(ip)%r(1:3) = saved_pos(1:3, ip)
356 IF (
PRESENT(subsys_qm) .AND.
PRESENT(qm_atom_index))
THEN
357 DO ip = 1,
SIZE(qm_atom_index)
358 subsys_qm%particles%els(ip)%r = subsys_mm%particles%els(qm_atom_index(ip))%r
362 DEALLOCATE (saved_pos)
376 INTEGER :: bigger_ip, i_dim, ip, max_ip, min_ip, &
377 smaller_ip, tmp_ip, unit_nr
378 INTEGER,
DIMENSION(:),
POINTER :: qm_atom_index
379 LOGICAL,
ALLOCATABLE :: avoid(:)
380 REAL(
dp) :: bigger_lat_dv, center_p(3), lat_dv, lat_dv3(3), lat_min(3), lat_p(3), &
381 max_coord_lat(3), min_coord_lat(3), smaller_lat_dv
382 REAL(
dp),
POINTER :: charges(:)
383 REAL(kind=
dp),
DIMENSION(3) :: max_coord, min_coord, transl_v
384 TYPE(
cell_type),
POINTER :: mm_cell, qm_cell
386 TYPE(
particle_type),
DIMENSION(:),
POINTER :: particles_mm, particles_qm
387 TYPE(
qs_kind_type),
DIMENSION(:),
POINTER :: qs_kind_set
390 NULLIFY (subsys_mm, subsys_qm, qm_atom_index, particles_mm, particles_qm, &
391 subsys_section, qm_cell, mm_cell, qs_kind_set)
393 cpassert(
ASSOCIATED(qmmm_env))
395 CALL fist_env_get(qmmm_env%fist_env, cell=mm_cell, subsys=subsys_mm)
396 CALL get_qs_env(qmmm_env%qs_env, cell=qm_cell, cp_subsys=subsys_qm)
397 qm_atom_index => qmmm_env%qm%qm_atom_index
398 cpassert(
ASSOCIATED(qm_atom_index))
400 particles_qm => subsys_qm%particles%els
401 particles_mm => subsys_mm%particles%els
402 IF (.NOT. qmmm_env%qm%center_qm_subsys0) qmmm_env%qm%do_translate = .false.
403 IF (qmmm_env%qm%do_translate)
THEN
404 IF (.NOT. qmmm_env%qm%center_qm_subsys_pbc_aware)
THEN
406 min_coord = huge(0.0_dp)
407 max_coord = -huge(0.0_dp)
408 DO ip = 1,
SIZE(qm_atom_index)
409 min_coord = min(min_coord, particles_mm(qm_atom_index(ip))%r)
410 max_coord = max(max_coord, particles_mm(qm_atom_index(ip))%r)
414 center_p = qmmm_pbc_aware_mean(particles_mm, mm_cell, qm_atom_index)
415 ALLOCATE (avoid(
SIZE(qm_atom_index)))
417 IF (mm_cell%perd(i_dim) /= 1)
THEN
419 min_coord_lat(i_dim) = huge(0.0_dp)
420 max_coord_lat(i_dim) = -huge(0.0_dp)
421 DO ip = 1,
SIZE(qm_atom_index)
422 lat_p = matmul(mm_cell%h_inv, particles_mm(qm_atom_index(ip))%r)
423 min_coord_lat(i_dim) = min(lat_p(i_dim), min_coord_lat(i_dim))
424 max_coord_lat(i_dim) = max(lat_p(i_dim), max_coord_lat(i_dim))
429 min_ip = qmmm_find_closest(particles_mm, mm_cell, qm_atom_index, avoid, center_p, i_dim, 0)
430 avoid(min_ip) = .true.
432 max_ip = qmmm_find_closest(particles_mm, mm_cell, qm_atom_index, avoid, &
433 particles_mm(qm_atom_index(min_ip))%r, i_dim, 0, lat_dv)
434 avoid(max_ip) = .true.
436 IF (lat_dv < 0.0)
THEN
442 DO WHILE (.NOT. all(avoid))
444 smaller_ip = qmmm_find_closest(particles_mm, mm_cell, qm_atom_index, &
445 avoid, particles_mm(qm_atom_index(min_ip))%r, i_dim, -1, smaller_lat_dv)
446 bigger_ip = qmmm_find_closest(particles_mm, mm_cell, qm_atom_index, &
447 avoid, particles_mm(qm_atom_index(max_ip))%r, i_dim, 1, bigger_lat_dv)
449 IF (abs(smaller_lat_dv) < abs(bigger_lat_dv))
THEN
451 avoid(min_ip) = .true.
454 avoid(max_ip) = .true.
458 lat_dv3 = qmmm_lat_dv(mm_cell, particles_mm(qm_atom_index(min_ip))%r, particles_mm(qm_atom_index(max_ip))%r)
459 IF (lat_dv3(i_dim) < 0.0_dp) lat_dv3(i_dim) = lat_dv3(i_dim) + 1.0_dp
460 lat_min = matmul(mm_cell%h_inv, particles_mm(qm_atom_index(min_ip))%r)
461 min_coord_lat(i_dim) = lat_min(i_dim)
462 max_coord_lat(i_dim) = lat_min(i_dim) + lat_dv3(i_dim)
466 min_coord = matmul(mm_cell%hmat, min_coord_lat)
467 max_coord = matmul(mm_cell%hmat, max_coord_lat)
470 transl_v = (max_coord + min_coord)/2.0_dp
476 transl_v(:) = transl_v(:) - sum(qm_cell%hmat, 2)/2.0_dp
478 IF (any(qmmm_env%qm%utrasl /= 1.0_dp))
THEN
479 transl_v = real(floor(transl_v/qmmm_env%qm%utrasl), kind=
dp)* &
482 qmmm_env%qm%transl_v = qmmm_env%qm%transl_v + transl_v
483 particles_mm => subsys_mm%particles%els
484 DO ip = 1, subsys_mm%particles%n_els
485 particles_mm(ip)%r = particles_mm(ip)%r - transl_v
487 IF (qmmm_env%qm%added_shells%num_mm_atoms > 0)
THEN
488 DO ip = 1, qmmm_env%qm%added_shells%num_mm_atoms
489 qmmm_env%qm%added_shells%added_particles(ip)%r = qmmm_env%qm%added_shells%added_particles(ip)%r - transl_v
490 qmmm_env%qm%added_shells%added_cores(ip)%r = qmmm_env%qm%added_shells%added_cores(ip)%r - transl_v
494 IF (unit_nr > 0)
WRITE (unit=unit_nr, fmt=
'(/1X,A)') &
495 " Translating the system in order to center the QM fragment in the QM box."
496 IF (.NOT. qmmm_env%qm%center_qm_subsys) qmmm_env%qm%do_translate = .false.
498 particles_mm => subsys_mm%particles%els
499 DO ip = 1,
SIZE(qm_atom_index)
500 particles_qm(ip)%r = particles_mm(qm_atom_index(ip))%r
505 CALL get_qs_env(qs_env=qmmm_env%qs_env, qs_kind_set=qs_kind_set)
507 ALLOCATE (charges(
SIZE(particles_mm)))
521 FUNCTION qmmm_pbc_aware_mean(particles_mm, mm_cell, qm_atom_index)
524 INTEGER,
DIMENSION(:),
POINTER :: qm_atom_index
525 REAL(
dp) :: qmmm_pbc_aware_mean(3)
527 COMPLEX(dp) :: mean_z(3)
531 DO ip = 1,
SIZE(qm_atom_index)
532 mean_z = mean_z + exp(
gaussi*2.0*
pi* &
533 matmul(mm_cell%h_inv, particles_mm(qm_atom_index(ip))%r))
535 mean_z = mean_z/abs(mean_z)
536 qmmm_pbc_aware_mean = matmul(mm_cell%hmat, &
538 END FUNCTION qmmm_pbc_aware_mean
547 FUNCTION qmmm_lat_dv(mm_cell, p1, p2)
549 REAL(
dp) :: p1(3), p2(3), qmmm_lat_dv(3)
551 REAL(
dp) :: lat_v1(3), lat_v2(3)
553 lat_v1 = matmul(mm_cell%h_inv, p1)
554 lat_v2 = matmul(mm_cell%h_inv, p2)
556 qmmm_lat_dv = lat_v2 - lat_v1
557 qmmm_lat_dv = qmmm_lat_dv - floor(qmmm_lat_dv)
558 END FUNCTION qmmm_lat_dv
573 FUNCTION qmmm_find_closest(particles_mm, mm_cell, qm_atom_index, avoid, p, i_dim, dir, closest_dv)
RESULT(closest_ip)
576 INTEGER,
DIMENSION(:),
POINTER :: qm_atom_index
579 INTEGER :: i_dim, dir
580 REAL(
dp),
OPTIONAL :: closest_dv
581 INTEGER :: closest_ip
584 REAL(
dp) :: lat_dv3(3), lat_dv_shifted, my_closest_dv
587 my_closest_dv = huge(0.0)
588 DO ip = 1,
SIZE(qm_atom_index)
590 lat_dv3 = qmmm_lat_dv(mm_cell, p, particles_mm(qm_atom_index(ip))%r)
592 lat_dv_shifted = lat_dv3(i_dim) + shift*1.0_dp
593 IF (abs(lat_dv_shifted) < abs(my_closest_dv) .AND. (dir*lat_dv_shifted >= 0.0))
THEN
594 my_closest_dv = lat_dv_shifted
600 IF (
PRESENT(closest_dv))
THEN
601 closest_dv = my_closest_dv
604 END FUNCTION qmmm_find_closest
616 REAL(kind=
dp),
DIMENSION(2),
INTENT(IN) :: spherical_cutoff
617 REAL(kind=
dp),
DIMENSION(3),
INTENT(IN) :: rij
618 REAL(kind=
dp),
INTENT(OUT) :: factor
620 REAL(kind=
dp) :: r, r0
622 r = sqrt(dot_product(rij, rij))
623 r0 = spherical_cutoff(1) - 20.0_dp*spherical_cutoff(2)
624 factor = 0.5_dp*(1.0_dp - tanh((r - r0)/spherical_cutoff(2)))
Handles all functions related to the CELL.
various routines to log and control the output. The idea is that decisions about where to log should ...
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 fist_env_get(fist_env, atomic_kind_set, particle_set, ewald_pw, local_particles, local_molecules, molecule_kind_set, molecule_set, cell, cell_ref, ewald_env, fist_nonbond_env, thermo, para_env, subsys, qmmm, qmmm_env, input, shell_model, shell_model_ad, shell_particle_set, core_particle_set, multipoles, results, exclusions, efield)
Purpose: Get the FIST environment.
Interface for the force calculations.
integer, parameter, public use_qmmm
integer, parameter, public use_qmmmx
Defines the basic variable types.
integer, parameter, public dp
An array-based list which grows on demand. When the internal array is full, a new array of twice the ...
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
complex(kind=dp), parameter, public gaussi
Define methods related to particle_type.
subroutine, public write_qs_particle_coordinates(particle_set, qs_kind_set, subsys_section, label)
Write the atomic coordinates to the output unit.
subroutine, public write_fist_particle_coordinates(particle_set, subsys_section, charges)
Write the atomic coordinates to the output unit.
Define the data structure for the particle information.
Basic container type for QM/MM.
subroutine, public apply_qmmm_unwrap(subsys_mm, subsys_qm, qm_atom_index, saved_pos)
...
subroutine, public apply_qmmm_walls_reflective(force_env)
Apply reflective QM walls in order to avoid QM atoms escaping from the QM Box.
subroutine, public apply_qmmm_walls(qmmm_env)
Apply QM quadratic walls in order to avoid QM atoms escaping from the QM Box.
subroutine, public spherical_cutoff_factor(spherical_cutoff, rij, factor)
Computes a spherical cutoff factor for the QMMM interactions.
subroutine, public apply_qmmm_translate(qmmm_env)
Apply translation to the full system in order to center the QM system into the QM box.
subroutine, public apply_qmmm_wrap(subsys_mm, mm_cell, subsys_qm, qm_atom_index, saved_pos)
wrap positions (with mm periodicity)
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, sab_cneo, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_ri_aux_kp, matrix_s, matrix_s_ri_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, rhoz_cneo_set, ecoul_1c, rho0_s_rs, rho0_s_gs, rhoz_cneo_s_rs, rhoz_cneo_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, harris_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, wanniercentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, eeq, rhs, do_rixs, tb_tblite)
Get the QUICKSTEP environment.
Define the quickstep kind type and their sub types.
Type defining parameters related to the simulation cell.
represents a system: atoms, molecules, their pos,vel,...
wrapper to abstract the force evaluation of the various methods
Provides all information about a quickstep kind.