Bottom-up computation of n-body gradient correction Exactly mirrors the energy MBE logic: deltaG = G - sum(all subset deltaGs) All gradients are in system coordinates, so subtraction is simple Bond connectivity is accessed via sys_geom%bonds
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | fragment_idx | |||
| integer, | intent(in) | :: | fragment(:) | |||
| type(fragment_lookup_t), | intent(in) | :: | lookup | |||
| type(calculation_result_t), | intent(in) | :: | results(:) | |||
| real(kind=dp), | intent(inout) | :: | delta_gradients(:,:,:) |
(3, total_atoms, fragment_count) |
||
| integer, | intent(in) | :: | n | |||
| type(system_geometry_t), | intent(in) | :: | sys_geom | |||
| type(comm_t), | intent(in), | optional | :: | world_comm |
MPI communicator for abort |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| logical, | private | :: | has_next | ||||
| integer, | private | :: | i | ||||
| integer, | private | :: | indices(MAX_MBE_LEVEL) | ||||
| integer, | private | :: | subset(MAX_MBE_LEVEL) | ||||
| integer(kind=int64), | private | :: | subset_idx | ||||
| integer, | private | :: | subset_size |
subroutine compute_mbe_gradient(fragment_idx, fragment, lookup, results, delta_gradients, n, sys_geom, world_comm) !! Bottom-up computation of n-body gradient correction !! Exactly mirrors the energy MBE logic: deltaG = G - sum(all subset deltaGs) !! All gradients are in system coordinates, so subtraction is simple !! Bond connectivity is accessed via sys_geom%bonds use mqc_result_types, only: calculation_result_t integer(int64), intent(in) :: fragment_idx integer, intent(in) :: fragment(:), n type(fragment_lookup_t), intent(in) :: lookup type(calculation_result_t), intent(in) :: results(:) real(dp), intent(inout) :: delta_gradients(:, :, :) !! (3, total_atoms, fragment_count) type(system_geometry_t), intent(in) :: sys_geom type(comm_t), intent(in), optional :: world_comm !! MPI communicator for abort integer :: subset_size, i integer :: indices(MAX_MBE_LEVEL), subset(MAX_MBE_LEVEL) ! Stack arrays to avoid heap contention integer(int64) :: subset_idx logical :: has_next ! Start with the full n-mer gradient mapped to system coordinates call map_fragment_to_system_gradient(results(fragment_idx)%gradient, fragment, & sys_geom, delta_gradients(:, :, fragment_idx), world_comm) ! Subtract all proper subsets (size 1 to n-1) ! This is EXACTLY like the energy calculation, but for each gradient component do subset_size = 1, n - 1 ! Initialize first combination do i = 1, subset_size indices(i) = i end do ! Loop through all combinations do ! Build current subset do i = 1, subset_size subset(i) = fragment(indices(i)) end do ! Look up subset index subset_idx = lookup%find(subset(1:subset_size), subset_size) if (subset_idx < 0) then call logger%error("Subset not found in MBE gradient computation") if (present(world_comm)) then call abort_comm(world_comm, 1) else error stop "Subset not found in MBE gradient!" end if end if ! Subtract pre-computed delta gradient (simple array subtraction in system coords) delta_gradients(:, :, fragment_idx) = delta_gradients(:, :, fragment_idx) - & delta_gradients(:, :, subset_idx) ! Get next combination call get_next_combination(indices, subset_size, n, has_next) if (.not. has_next) exit end do end do end subroutine compute_mbe_gradient