compute_gmbe Subroutine

public subroutine compute_gmbe(monomers, n_monomers, monomer_results, n_intersections, intersection_results, intersection_sets, intersection_levels, total_energy, sys_geom, total_gradient, total_hessian, bonds, world_comm)

Uses

  • proc~~compute_gmbe~~UsesGraph proc~compute_gmbe compute_gmbe module~mqc_config_parser mqc_config_parser proc~compute_gmbe->module~mqc_config_parser module~mqc_error mqc_error proc~compute_gmbe->module~mqc_error module~mqc_gmbe_utils mqc_gmbe_utils proc~compute_gmbe->module~mqc_gmbe_utils module~mqc_physical_fragment mqc_physical_fragment proc~compute_gmbe->module~mqc_physical_fragment module~mqc_result_types mqc_result_types proc~compute_gmbe->module~mqc_result_types module~mqc_config_parser->module~mqc_error module~mqc_config_parser->module~mqc_physical_fragment module~mqc_calc_types mqc_calc_types module~mqc_config_parser->module~mqc_calc_types module~mqc_calculation_defaults mqc_calculation_defaults module~mqc_config_parser->module~mqc_calculation_defaults module~mqc_geometry mqc_geometry module~mqc_config_parser->module~mqc_geometry module~mqc_method_types mqc_method_types module~mqc_config_parser->module~mqc_method_types pic_types pic_types module~mqc_config_parser->pic_types module~mqc_gmbe_utils->module~mqc_error module~mqc_gmbe_utils->module~mqc_physical_fragment module~mqc_gmbe_utils->module~mqc_result_types module~mqc_combinatorics mqc_combinatorics module~mqc_gmbe_utils->module~mqc_combinatorics pic_io pic_io module~mqc_gmbe_utils->pic_io pic_logger pic_logger module~mqc_gmbe_utils->pic_logger module~mqc_gmbe_utils->pic_types module~mqc_physical_fragment->module~mqc_error module~mqc_cgto mqc_cgto module~mqc_physical_fragment->module~mqc_cgto module~mqc_elements mqc_elements module~mqc_physical_fragment->module~mqc_elements module~mqc_physical_fragment->module~mqc_geometry module~mqc_physical_constants mqc_physical_constants module~mqc_physical_fragment->module~mqc_physical_constants module~mqc_xyz_reader mqc_xyz_reader module~mqc_physical_fragment->module~mqc_xyz_reader module~mqc_physical_fragment->pic_types module~mqc_result_types->module~mqc_error pic_mpi_lib pic_mpi_lib module~mqc_result_types->pic_mpi_lib module~mqc_result_types->pic_types module~mqc_calc_types->pic_types module~mqc_calculation_defaults->pic_types module~mqc_cgto->pic_types module~mqc_combinatorics->pic_types module~mqc_elements->pic_types pic_ascii pic_ascii module~mqc_elements->pic_ascii module~mqc_geometry->pic_types module~mqc_method_types->pic_types module~mqc_physical_constants->pic_types module~mqc_xyz_reader->module~mqc_error module~mqc_xyz_reader->module~mqc_geometry module~mqc_xyz_reader->pic_types

Compute generalized many-body expansion (GMBE) energy with optional gradient and/or hessian

This is the core routine that handles all GMBE computations using the inclusion-exclusion principle for overlapping fragments. Optional arguments control what derivatives are computed: - If sys_geom and total_gradient are present: compute gradient - If total_hessian is also present: compute hessian

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: monomers(:)
integer, intent(in) :: n_monomers
type(calculation_result_t), intent(in) :: monomer_results(:)
integer, intent(in) :: n_intersections
type(calculation_result_t), intent(in), optional :: intersection_results(:)
integer, intent(in), optional :: intersection_sets(:,:)
integer, intent(in), optional :: intersection_levels(:)
real(kind=dp), intent(out) :: total_energy
type(system_geometry_t), intent(in), optional :: sys_geom
real(kind=dp), intent(out), optional :: total_gradient(:,:)
real(kind=dp), intent(out), optional :: total_hessian(:,:)
type(bond_t), intent(in), optional :: bonds(:)
type(comm_t), intent(in), optional :: world_comm

Calls

proc~~compute_gmbe~~CallsGraph proc~compute_gmbe compute_gmbe abort_comm abort_comm proc~compute_gmbe->abort_comm cart_disp cart_disp proc~compute_gmbe->cart_disp configuration configuration proc~compute_gmbe->configuration error error proc~compute_gmbe->error fc_mdyne fc_mdyne proc~compute_gmbe->fc_mdyne force_constants force_constants proc~compute_gmbe->force_constants frequencies frequencies proc~compute_gmbe->frequencies info info proc~compute_gmbe->info proc~build_fragment_from_indices build_fragment_from_indices proc~compute_gmbe->proc~build_fragment_from_indices proc~compute_vibrational_analysis compute_vibrational_analysis proc~compute_gmbe->proc~compute_vibrational_analysis proc~energy_total energy_t%energy_total proc~compute_gmbe->proc~energy_total proc~error_get_full_trace error_t%error_get_full_trace proc~compute_gmbe->proc~error_get_full_trace proc~error_has_error error_t%error_has_error proc~compute_gmbe->proc~error_has_error proc~fragment_destroy physical_fragment_t%fragment_destroy proc~compute_gmbe->proc~fragment_destroy proc~print_gmbe_energy_breakdown print_gmbe_energy_breakdown proc~compute_gmbe->proc~print_gmbe_energy_breakdown proc~print_gmbe_gradient_info print_gmbe_gradient_info proc~compute_gmbe->proc~print_gmbe_gradient_info proc~print_gmbe_intersection_debug print_gmbe_intersection_debug proc~compute_gmbe->proc~print_gmbe_intersection_debug proc~print_vibrational_analysis print_vibrational_analysis proc~compute_gmbe->proc~print_vibrational_analysis proc~process_intersection_derivatives process_intersection_derivatives proc~compute_gmbe->proc~process_intersection_derivatives proc~redistribute_cap_gradients redistribute_cap_gradients proc~compute_gmbe->proc~redistribute_cap_gradients proc~redistribute_cap_hessian redistribute_cap_hessian proc~compute_gmbe->proc~redistribute_cap_hessian reduced_masses reduced_masses proc~compute_gmbe->reduced_masses to_char to_char proc~compute_gmbe->to_char proc~build_fragment_from_indices->proc~error_has_error proc~add_hydrogen_caps add_hydrogen_caps proc~build_fragment_from_indices->proc~add_hydrogen_caps proc~calculate_monomer_distance calculate_monomer_distance proc~build_fragment_from_indices->proc~calculate_monomer_distance proc~check_duplicate_atoms check_duplicate_atoms proc~build_fragment_from_indices->proc~check_duplicate_atoms proc~count_hydrogen_caps count_hydrogen_caps proc~build_fragment_from_indices->proc~count_hydrogen_caps proc~error_add_context error_t%error_add_context proc~build_fragment_from_indices->proc~error_add_context proc~fragment_compute_nelec physical_fragment_t%fragment_compute_nelec proc~build_fragment_from_indices->proc~fragment_compute_nelec proc~compute_cartesian_displacements compute_cartesian_displacements proc~compute_vibrational_analysis->proc~compute_cartesian_displacements proc~compute_force_constants compute_force_constants proc~compute_vibrational_analysis->proc~compute_force_constants proc~compute_ir_intensities compute_ir_intensities proc~compute_vibrational_analysis->proc~compute_ir_intensities proc~compute_reduced_masses compute_reduced_masses proc~compute_vibrational_analysis->proc~compute_reduced_masses proc~compute_vibrational_frequencies compute_vibrational_frequencies proc~compute_vibrational_analysis->proc~compute_vibrational_frequencies proc~mp2_total mp2_energy_t%mp2_total proc~energy_total->proc~mp2_total proc~error_get_full_trace->proc~error_has_error proc~basis_set_destroy molecular_basis_type%basis_set_destroy proc~fragment_destroy->proc~basis_set_destroy proc~print_gmbe_energy_breakdown->info proc~print_gmbe_gradient_info->info proc~print_gmbe_gradient_info->to_char proc~print_gmbe_intersection_debug->proc~energy_total debug debug proc~print_gmbe_intersection_debug->debug proc~print_vibrational_analysis->info proc~compute_thermochemistry compute_thermochemistry proc~print_vibrational_analysis->proc~compute_thermochemistry proc~element_number_to_symbol element_number_to_symbol proc~print_vibrational_analysis->proc~element_number_to_symbol proc~print_thermochemistry print_thermochemistry proc~print_vibrational_analysis->proc~print_thermochemistry warning warning proc~print_vibrational_analysis->warning proc~process_intersection_derivatives->abort_comm proc~process_intersection_derivatives->error proc~process_intersection_derivatives->proc~error_get_full_trace proc~process_intersection_derivatives->proc~error_has_error proc~process_intersection_derivatives->proc~fragment_destroy proc~process_intersection_derivatives->proc~redistribute_cap_gradients proc~process_intersection_derivatives->proc~redistribute_cap_hessian proc~build_fragment_from_atom_list build_fragment_from_atom_list proc~process_intersection_derivatives->proc~build_fragment_from_atom_list proc~find_fragment_intersection find_fragment_intersection proc~process_intersection_derivatives->proc~find_fragment_intersection proc~get_monomer_atom_list get_monomer_atom_list proc~process_intersection_derivatives->proc~get_monomer_atom_list proc~process_intersection_derivatives->warning proc~atomic_basis_destroy atomic_basis_type%atomic_basis_destroy proc~basis_set_destroy->proc~atomic_basis_destroy proc~build_fragment_from_atom_list->proc~error_has_error proc~build_fragment_from_atom_list->proc~add_hydrogen_caps proc~build_fragment_from_atom_list->proc~check_duplicate_atoms proc~build_fragment_from_atom_list->proc~count_hydrogen_caps proc~build_fragment_from_atom_list->proc~error_add_context proc~build_fragment_from_atom_list->proc~fragment_compute_nelec proc~to_angstrom to_angstrom proc~calculate_monomer_distance->proc~to_angstrom proc~check_duplicate_atoms->error proc~check_duplicate_atoms->to_char proc~check_duplicate_atoms->proc~element_number_to_symbol proc~error_set error_t%error_set proc~check_duplicate_atoms->proc~error_set proc~element_mass element_mass proc~compute_cartesian_displacements->proc~element_mass proc~compute_ir_intensities->proc~element_mass proc~compute_reduced_masses->proc~element_mass proc~compute_electronic_entropy compute_electronic_entropy proc~compute_thermochemistry->proc~compute_electronic_entropy proc~compute_moments_of_inertia compute_moments_of_inertia proc~compute_thermochemistry->proc~compute_moments_of_inertia proc~compute_partition_functions compute_partition_functions proc~compute_thermochemistry->proc~compute_partition_functions proc~compute_rotational_constants compute_rotational_constants proc~compute_thermochemistry->proc~compute_rotational_constants proc~compute_rotational_thermo compute_rotational_thermo proc~compute_thermochemistry->proc~compute_rotational_thermo proc~compute_translational_thermo compute_translational_thermo proc~compute_thermochemistry->proc~compute_translational_thermo proc~compute_vibrational_thermo compute_vibrational_thermo proc~compute_thermochemistry->proc~compute_vibrational_thermo proc~compute_zpe compute_zpe proc~compute_thermochemistry->proc~compute_zpe proc~compute_vibrational_frequencies->error proc~compute_vibrational_frequencies->warning pic_syev pic_syev proc~compute_vibrational_frequencies->pic_syev proc~mass_weight_hessian mass_weight_hessian proc~compute_vibrational_frequencies->proc~mass_weight_hessian proc~project_translation_rotation project_translation_rotation proc~compute_vibrational_frequencies->proc~project_translation_rotation proc~print_thermochemistry->info proc~cgto_destroy cgto_type%cgto_destroy proc~atomic_basis_destroy->proc~cgto_destroy proc~compute_moments_of_inertia->to_char proc~compute_moments_of_inertia->warning proc~compute_moments_of_inertia->pic_syev proc~compute_moments_of_inertia->proc~element_mass proc~compute_zpe->to_char proc~compute_zpe->warning proc~mass_weight_hessian->proc~element_mass proc~project_translation_rotation->proc~element_mass pic_gesvd pic_gesvd proc~project_translation_rotation->pic_gesvd

Variables

Type Visibility Attributes Name Initial
logical, private :: compute_grad
logical, private :: compute_hess
integer, private :: current_log_level
type(error_t), private :: error
type(physical_fragment_t), private :: fragment
logical, private :: has_intersections
integer, private :: hess_dim
integer, private :: i
integer, private :: k
integer, private, allocatable :: level_counts(:)
real(kind=dp), private, allocatable :: level_energies(:)
integer, private :: max_level
real(kind=dp), private :: monomer_energy
integer, private, allocatable :: monomer_idx(:)
real(kind=dp), private :: sign_factor

Source Code

   subroutine compute_gmbe(monomers, n_monomers, monomer_results, &
                           n_intersections, intersection_results, &
                           intersection_sets, intersection_levels, &
                           total_energy, &
                           sys_geom, total_gradient, total_hessian, bonds, world_comm)
      !! Compute generalized many-body expansion (GMBE) energy with optional gradient and/or hessian
      !!
      !! This is the core routine that handles all GMBE computations using
      !! the inclusion-exclusion principle for overlapping fragments.
      !! Optional arguments control what derivatives are computed:
      !!   - If sys_geom and total_gradient are present: compute gradient
      !!   - If total_hessian is also present: compute hessian
      use mqc_result_types, only: calculation_result_t
      use mqc_physical_fragment, only: build_fragment_from_indices, build_fragment_from_atom_list, &
                                       redistribute_cap_gradients, redistribute_cap_hessian
      use mqc_gmbe_utils, only: find_fragment_intersection
      use mqc_config_parser, only: bond_t
      use mqc_error, only: error_t

      ! Required arguments
      integer, intent(in) :: monomers(:)
      integer, intent(in) :: n_monomers
      type(calculation_result_t), intent(in) :: monomer_results(:)
      integer, intent(in) :: n_intersections
      type(calculation_result_t), intent(in), optional :: intersection_results(:)
      integer, intent(in), optional :: intersection_sets(:, :)
      integer, intent(in), optional :: intersection_levels(:)
      real(dp), intent(out) :: total_energy

      ! Optional arguments for gradient computation
      type(system_geometry_t), intent(in), optional :: sys_geom
      real(dp), intent(out), optional :: total_gradient(:, :)

      ! Optional arguments for hessian computation
      real(dp), intent(out), optional :: total_hessian(:, :)

      ! Optional bond information for hydrogen cap handling
      type(bond_t), intent(in), optional :: bonds(:)

      ! Optional MPI communicator for abort
      type(comm_t), intent(in), optional :: world_comm

      ! Local variables
      integer :: i, k, max_level, current_log_level, hess_dim
      real(dp) :: monomer_energy, sign_factor
      real(dp), allocatable :: level_energies(:)
      integer, allocatable :: level_counts(:)
      type(physical_fragment_t) :: fragment
      type(error_t) :: error
      integer, allocatable :: monomer_idx(:)
      logical :: compute_grad, compute_hess, has_intersections

      ! Determine what to compute based on optional arguments
      compute_grad = present(sys_geom) .and. present(total_gradient)
      compute_hess = compute_grad .and. present(total_hessian)
      has_intersections = n_intersections > 0 .and. present(intersection_results) .and. &
                          present(intersection_sets) .and. present(intersection_levels)

      ! Initialize outputs
      if (compute_grad) then
         total_gradient = 0.0_dp
      end if
      if (compute_hess) then
         total_hessian = 0.0_dp
         hess_dim = 3*sys_geom%total_atoms
      end if

      ! Sum monomer energies (and gradients/hessians if requested)
      monomer_energy = 0.0_dp
      do i = 1, n_monomers
         monomer_energy = monomer_energy + monomer_results(i)%energy%total()

         ! Accumulate monomer derivatives if requested
         if (compute_grad .and. monomer_results(i)%has_gradient) then
            allocate (monomer_idx(1))
            monomer_idx(1) = monomers(i)
            call build_fragment_from_indices(sys_geom, monomer_idx, fragment, error, bonds)
            if (error%has_error()) then
               call logger%error(error%get_full_trace())
               if (present(world_comm)) then
                  call abort_comm(world_comm, 1)
               else
                  error stop "Failed to build monomer fragment in GMBE"
               end if
            end if
            call redistribute_cap_gradients(fragment, monomer_results(i)%gradient, total_gradient)
            if (compute_hess .and. monomer_results(i)%has_hessian) then
               call redistribute_cap_hessian(fragment, monomer_results(i)%hessian, total_hessian)
            end if
            call fragment%destroy()
            deallocate (monomer_idx)
         end if
      end do

      ! Start with monomer contribution
      total_energy = monomer_energy

      ! Handle intersections with inclusion-exclusion
      if (has_intersections) then
         max_level = maxval(intersection_levels)

         allocate (level_energies(max_level))
         allocate (level_counts(max_level))
         level_energies = 0.0_dp
         level_counts = 0

         ! Process intersection energies and derivatives
         do i = 1, n_intersections
            k = intersection_levels(i)
            sign_factor = real((-1)**(k + 1), dp)
            level_energies(k) = level_energies(k) + intersection_results(i)%energy%total()
            level_counts(k) = level_counts(k) + 1

            ! Handle intersection derivatives if requested
            if (compute_grad .and. (intersection_results(i)%has_gradient .or. &
                                    (compute_hess .and. intersection_results(i)%has_hessian))) then
               call process_intersection_derivatives(i, k, sign_factor, intersection_results, &
                                                     intersection_sets, sys_geom, total_gradient, total_hessian, bonds, &
                                                     compute_grad, compute_hess, hess_dim, world_comm)
            end if
         end do

         ! Apply inclusion-exclusion to energy
         do k = 2, max_level
            if (level_counts(k) > 0) then
               sign_factor = real((-1)**(k + 1), dp)
               total_energy = total_energy + sign_factor*level_energies(k)
            end if
         end do

         ! Print energy breakdown
         call print_gmbe_energy_breakdown(monomer_energy, n_monomers, level_energies, level_counts, &
                                          max_level, total_energy, .true.)

         ! Print debug info for intersections
         call print_gmbe_intersection_debug(n_intersections, n_monomers, intersection_sets, &
                                            intersection_levels, intersection_results)

         deallocate (level_energies, level_counts)
      else
         ! No intersections - just print monomer sum
         call print_gmbe_energy_breakdown(monomer_energy, n_monomers, level_energies, level_counts, &
                                          0, total_energy, .false.)
      end if

      ! Print gradient/hessian info
      if (compute_grad) then
         call logger%configuration(level=current_log_level)
         call print_gmbe_gradient_info(total_gradient, sys_geom, current_log_level)
      end if

      if (compute_hess) then
         call logger%info("GMBE Hessian computation completed")
         call logger%info("  Total Hessian Frobenius norm: "//to_char(sqrt(sum(total_hessian**2))))

         ! Compute and print full vibrational analysis
         block
            real(dp), allocatable :: frequencies(:), reduced_masses(:), force_constants(:)
            real(dp), allocatable :: cart_disp(:, :), fc_mdyne(:)

            call logger%info("  Computing vibrational analysis (projecting trans/rot modes)...")
            call compute_vibrational_analysis(total_hessian, sys_geom%element_numbers, frequencies, &
                                              reduced_masses, force_constants, cart_disp, &
                                              coordinates=sys_geom%coordinates, &
                                              project_trans_rot=.true., &
                                              force_constants_mdyne=fc_mdyne)

            if (allocated(frequencies)) then
               call print_vibrational_analysis(frequencies, reduced_masses, force_constants, &
                                               cart_disp, sys_geom%element_numbers, &
                                               force_constants_mdyne=fc_mdyne, &
                                               coordinates=sys_geom%coordinates, &
                                               electronic_energy=total_energy)
               deallocate (frequencies, reduced_masses, force_constants, cart_disp, fc_mdyne)
            end if
         end block
      end if

   end subroutine compute_gmbe