Wrapper to handle the evaluation of dispersion energy and derivatives
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(structure_type), | intent(in) | :: | mol |
Molecular structure data |
||
| class(dispersion_model), | intent(in) | :: | disp |
Dispersion model |
||
| class(damping_param), | intent(in) | :: | param |
Damping parameters |
||
| type(realspace_cutoff), | intent(in) | :: | cutoff |
Realspace cutoffs |
||
| real(kind=wp), | intent(out) | :: | energy |
Dispersion energy |
||
| real(kind=wp), | intent(out), | optional, | contiguous | :: | gradient(:,:) |
Dispersion gradient |
| real(kind=wp), | intent(out), | optional, | contiguous | :: | sigma(:,:) |
Dispersion virial |
| type(work_partition), | intent(in), | optional | :: | partition |
Optional externally assigned work partition |
|
| type(error_type), | intent(out), | optional, | allocatable | :: | error |
Error on failure; failed calculations return NaN results. |
subroutine get_dispersion(mol, disp, param, cutoff, energy, gradient, sigma, partition, error) !DEC$ ATTRIBUTES DLLEXPORT :: get_dispersion !> Molecular structure data class(structure_type), intent(in) :: mol !> Dispersion model class(dispersion_model), intent(in) :: disp !> Damping parameters class(damping_param), intent(in) :: param !> Realspace cutoffs type(realspace_cutoff), intent(in) :: cutoff !> Dispersion energy real(wp), intent(out) :: energy !> Dispersion gradient real(wp), intent(out), contiguous, optional :: gradient(:, :) !> Dispersion virial real(wp), intent(out), contiguous, optional :: sigma(:, :) !> Optional externally assigned work partition type(work_partition), intent(in), optional :: partition !> Error on failure; failed calculations return NaN results. type(error_type), allocatable, intent(out), optional :: error logical :: grad integer :: mref real(wp), allocatable :: cn(:) real(wp), allocatable :: q(:), dqdr(:, :, :), dqdL(:, :, :) real(wp), allocatable :: gwvec(:, :, :), gwdcn(:, :, :), gwdq(:, :, :) real(wp), allocatable :: c6(:, :), dc6dcn(:, :), dc6dq(:, :) real(wp), allocatable :: dEdcn(:), dEdq(:), energies(:) real(wp), allocatable :: lattr(:, :) type(error_type), allocatable :: local_error energy = ieee_value(0.0_wp, ieee_quiet_nan) if (present(gradient)) gradient = ieee_value(0.0_wp, ieee_quiet_nan) if (present(sigma)) sigma = ieee_value(0.0_wp, ieee_quiet_nan) mref = maxval(disp%ref) grad = present(gradient).or.present(sigma) if (.not. allocated(disp%mchrg)) then if (present(error)) call fatal_error(error, "Not supported for non-self-consistent D4 version") return end if allocate(cn(mol%nat)) call get_lattice_points(mol%periodic, mol%lattice, cutoff%cn, lattr) call get_coordination_number(mol, lattr, cutoff%cn, disp%rcov, disp%en, cn, error=local_error) if (allocated(local_error)) then if (present(error)) call move_alloc(local_error, error) return end if allocate(q(mol%nat)) if (grad) allocate(dqdr(3, mol%nat, mol%nat), dqdL(3, 3, mol%nat)) call get_charges(disp%mchrg, mol, local_error, q, dqdr, dqdL) if (allocated(local_error)) then if (present(error)) call move_alloc(local_error, error) return end if allocate(gwvec(mref, mol%nat, disp%ncoup)) if (grad) allocate(gwdcn(mref, mol%nat, disp%ncoup), gwdq(mref, mol%nat, disp%ncoup)) call disp%weight_references(mol, cn, q, gwvec, gwdcn, gwdq) allocate(c6(mol%nat, mol%nat)) if (grad) allocate(dc6dcn(mol%nat, mol%nat), dc6dq(mol%nat, mol%nat)) call disp%get_atomic_c6(mol, gwvec, gwdcn, gwdq, c6, dc6dcn, dc6dq) allocate(energies(mol%nat)) energies(:) = 0.0_wp if (grad) then allocate(dEdcn(mol%nat), dEdq(mol%nat)) dEdcn(:) = 0.0_wp dEdq(:) = 0.0_wp gradient(:, :) = 0.0_wp sigma(:, :) = 0.0_wp end if call get_lattice_points(mol%periodic, mol%lattice, cutoff%disp2, lattr) call param%get_dispersion2(mol, lattr, cutoff%disp2, cutoff%width2, & & disp%r4r2, c6, dc6dcn, dc6dq, energies, dEdcn, dEdq, gradient, & & sigma, partition) if (grad) then call d4_gemv(dqdr, dEdq, gradient, beta=1.0_wp) call d4_gemv(dqdL, dEdq, sigma, beta=1.0_wp) end if q(:) = 0.0_wp call disp%weight_references(mol, cn, q, gwvec, gwdcn, gwdq) call disp%get_atomic_c6(mol, gwvec, gwdcn, gwdq, c6, dc6dcn, dc6dq) call get_lattice_points(mol%periodic, mol%lattice, cutoff%disp3, lattr) call param%get_dispersion3(mol, lattr, cutoff%disp3, cutoff%width3, & & disp%r4r2, c6, dc6dcn, dc6dq, energies, dEdcn, dEdq, gradient, & & sigma, partition) if (grad) then call add_coordination_number_derivs(mol, lattr, cutoff%cn, & & disp%rcov, disp%en, dEdcn, gradient, sigma, error=local_error) if (allocated(local_error)) then if (present(error)) call move_alloc(local_error, error) return end if end if energy = sum(energies) end subroutine get_dispersion