unfragmented_calculation Module Subroutine

module subroutine unfragmented_calculation(sys_geom, config, result_out, json_data)

Uses

  • proc~~unfragmented_calculation~~UsesGraph proc~unfragmented_calculation unfragmented_calculation module~mqc_error mqc_error proc~unfragmented_calculation->module~mqc_error module~mqc_json_output_types mqc_json_output_types proc~unfragmented_calculation->module~mqc_json_output_types module~mqc_thermochemistry mqc_thermochemistry proc~unfragmented_calculation->module~mqc_thermochemistry module~mqc_vibrational_analysis mqc_vibrational_analysis proc~unfragmented_calculation->module~mqc_vibrational_analysis module~mqc_json_output_types->module~mqc_thermochemistry pic_types pic_types module~mqc_json_output_types->pic_types module~mqc_elements mqc_elements module~mqc_thermochemistry->module~mqc_elements module~mqc_physical_constants mqc_physical_constants module~mqc_thermochemistry->module~mqc_physical_constants pic_io pic_io module~mqc_thermochemistry->pic_io pic_lapack_interfaces pic_lapack_interfaces module~mqc_thermochemistry->pic_lapack_interfaces pic_logger pic_logger module~mqc_thermochemistry->pic_logger module~mqc_thermochemistry->pic_types module~mqc_vibrational_analysis->module~mqc_thermochemistry module~mqc_vibrational_analysis->module~mqc_elements module~mqc_vibrational_analysis->module~mqc_physical_constants module~mqc_vibrational_analysis->pic_lapack_interfaces module~mqc_vibrational_analysis->pic_logger module~mqc_vibrational_analysis->pic_types module~mqc_elements->pic_types pic_ascii pic_ascii module~mqc_elements->pic_ascii module~mqc_physical_constants->pic_types

Run unfragmented calculation on the entire system (nlevel=0) This is a simple single-process calculation without MPI distribution If result_out is present, returns result instead of writing JSON and destroying it If json_data is present, populates it for centralized JSON output

Arguments

Type IntentOptional Attributes Name
type(system_geometry_t), intent(in) :: sys_geom
type(driver_config_t), intent(in) :: config

Driver configuration (includes method_config, calc_type, etc.)

type(calculation_result_t), intent(out), optional :: result_out
type(json_output_data_t), intent(out), optional :: json_data

Calls

proc~~unfragmented_calculation~~CallsGraph proc~unfragmented_calculation unfragmented_calculation cart_disp cart_disp proc~unfragmented_calculation->cart_disp configuration configuration proc~unfragmented_calculation->configuration eigenvalues eigenvalues proc~unfragmented_calculation->eigenvalues error error proc~unfragmented_calculation->error fc_mdyne fc_mdyne proc~unfragmented_calculation->fc_mdyne force_constants force_constants proc~unfragmented_calculation->force_constants frequencies frequencies proc~unfragmented_calculation->frequencies info info proc~unfragmented_calculation->info interface~do_fragment_work do_fragment_work proc~unfragmented_calculation->interface~do_fragment_work ir_intensities ir_intensities proc~unfragmented_calculation->ir_intensities proc~check_duplicate_atoms check_duplicate_atoms proc~unfragmented_calculation->proc~check_duplicate_atoms proc~compute_thermochemistry compute_thermochemistry proc~unfragmented_calculation->proc~compute_thermochemistry proc~compute_vibrational_analysis compute_vibrational_analysis proc~unfragmented_calculation->proc~compute_vibrational_analysis proc~compute_vibrational_frequencies compute_vibrational_frequencies proc~unfragmented_calculation->proc~compute_vibrational_frequencies proc~energy_total energy_t%energy_total proc~unfragmented_calculation->proc~energy_total proc~error_get_full_trace error_t%error_get_full_trace proc~unfragmented_calculation->proc~error_get_full_trace proc~error_get_message error_t%error_get_message proc~unfragmented_calculation->proc~error_get_message proc~error_has_error error_t%error_has_error proc~unfragmented_calculation->proc~error_has_error proc~fragment_compute_nelec physical_fragment_t%fragment_compute_nelec proc~unfragmented_calculation->proc~fragment_compute_nelec proc~print_vibrational_analysis print_vibrational_analysis proc~unfragmented_calculation->proc~print_vibrational_analysis proc~result_destroy calculation_result_t%result_destroy proc~unfragmented_calculation->proc~result_destroy projected_hessian projected_hessian proc~unfragmented_calculation->projected_hessian reduced_masses reduced_masses proc~unfragmented_calculation->reduced_masses to_char to_char proc~unfragmented_calculation->to_char proc~do_fragment_work do_fragment_work interface~do_fragment_work->proc~do_fragment_work proc~check_duplicate_atoms->error proc~check_duplicate_atoms->to_char proc~element_number_to_symbol element_number_to_symbol proc~check_duplicate_atoms->proc~element_number_to_symbol proc~error_set error_t%error_set proc~check_duplicate_atoms->proc~error_set 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_analysis->proc~compute_vibrational_frequencies 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->error 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 warning warning proc~compute_vibrational_frequencies->warning proc~mp2_total mp2_energy_t%mp2_total proc~energy_total->proc~mp2_total proc~error_get_full_trace->proc~error_has_error proc~print_vibrational_analysis->info proc~print_vibrational_analysis->proc~compute_thermochemistry proc~print_vibrational_analysis->proc~element_number_to_symbol proc~print_thermochemistry print_thermochemistry proc~print_vibrational_analysis->proc~print_thermochemistry proc~print_vibrational_analysis->warning proc~result_reset calculation_result_t%result_reset proc~result_destroy->proc~result_reset proc~element_mass element_mass proc~compute_cartesian_displacements->proc~element_mass proc~compute_ir_intensities->proc~element_mass proc~compute_moments_of_inertia->to_char proc~compute_moments_of_inertia->pic_syev proc~compute_moments_of_inertia->warning proc~compute_moments_of_inertia->proc~element_mass proc~compute_reduced_masses->proc~element_mass proc~compute_zpe->to_char proc~compute_zpe->warning proc~do_fragment_work->configuration proc~do_fragment_work->to_char proc~do_fragment_work->proc~error_set calc_energy calc_energy proc~do_fragment_work->calc_energy calc_gradient calc_gradient proc~do_fragment_work->calc_gradient calc_hessian calc_hessian proc~do_fragment_work->calc_hessian proc~calc_type_to_string calc_type_to_string proc~do_fragment_work->proc~calc_type_to_string proc~create_method create_method proc~do_fragment_work->proc~create_method proc~energy_reset energy_t%energy_reset proc~do_fragment_work->proc~energy_reset proc~error_add_context error_t%error_add_context proc~do_fragment_work->proc~error_add_context proc~print_fragment_xyz print_fragment_xyz proc~do_fragment_work->proc~print_fragment_xyz proc~mass_weight_hessian->proc~element_mass proc~print_thermochemistry->info pic_gesvd pic_gesvd proc~project_translation_rotation->pic_gesvd proc~project_translation_rotation->proc~element_mass proc~result_reset->proc~energy_reset proc~error_clear error_t%error_clear proc~result_reset->proc~error_clear proc~factory_create method_factory_t%factory_create proc~create_method->proc~factory_create proc~mp2_reset mp2_energy_t%mp2_reset proc~energy_reset->proc~mp2_reset proc~print_fragment_xyz->info proc~print_fragment_xyz->to_char proc~print_fragment_xyz->proc~element_number_to_symbol proc~to_angstrom to_angstrom proc~print_fragment_xyz->proc~to_angstrom proc~configure_dft configure_dft proc~factory_create->proc~configure_dft proc~configure_hf configure_hf proc~factory_create->proc~configure_hf proc~configure_mcscf configure_mcscf proc~factory_create->proc~configure_mcscf proc~configure_xtb configure_xtb proc~factory_create->proc~configure_xtb

Called by

proc~~unfragmented_calculation~~CalledByGraph proc~unfragmented_calculation unfragmented_calculation interface~unfragmented_calculation unfragmented_calculation interface~unfragmented_calculation->proc~unfragmented_calculation proc~run_unfragmented_calculation run_unfragmented_calculation proc~run_unfragmented_calculation->interface~unfragmented_calculation proc~run_calculation run_calculation proc~run_calculation->proc~run_unfragmented_calculation proc~compute_energy_and_forces compute_energy_and_forces proc~compute_energy_and_forces->proc~run_calculation proc~run_multi_molecule_calculations run_multi_molecule_calculations proc~run_multi_molecule_calculations->proc~run_calculation program~main main program~main->proc~run_calculation program~main->proc~run_multi_molecule_calculations

Variables

Type Visibility Attributes Name Initial
type(error_t), private :: error
type(physical_fragment_t), private :: full_system
integer, private :: i
type(calculation_result_t), private :: result
integer, private :: total_atoms

Source Code

   module subroutine unfragmented_calculation(sys_geom, config, result_out, json_data)
      !! Run unfragmented calculation on the entire system (nlevel=0)
      !! This is a simple single-process calculation without MPI distribution
      !! If result_out is present, returns result instead of writing JSON and destroying it
      !! If json_data is present, populates it for centralized JSON output
      use mqc_error, only: error_t
      use mqc_vibrational_analysis, only: compute_vibrational_frequencies, &
                                          compute_vibrational_analysis, print_vibrational_analysis
      use mqc_thermochemistry, only: thermochemistry_result_t, compute_thermochemistry
      use mqc_json_output_types, only: json_output_data_t, OUTPUT_MODE_UNFRAGMENTED
      type(system_geometry_t), intent(in) :: sys_geom
      type(driver_config_t), intent(in) :: config  !! Driver configuration (includes method_config, calc_type, etc.)
      type(calculation_result_t), intent(out), optional :: result_out
      type(json_output_data_t), intent(out), optional :: json_data

      type(calculation_result_t) :: result
      integer :: total_atoms
      type(physical_fragment_t) :: full_system
      type(error_t) :: error
      integer :: i

      total_atoms = sys_geom%total_atoms

      call logger%info("============================================")
      call logger%info("Running unfragmented calculation")
      call logger%info("  Total atoms: "//to_char(total_atoms))
      call logger%info("============================================")

      ! Build the full system as a single fragment
      ! For overlapping fragments, we use the full system directly (not concatenating fragments)
      full_system%n_atoms = total_atoms
      full_system%n_caps = 0
      allocate (full_system%element_numbers(total_atoms))
      allocate (full_system%coordinates(3, total_atoms))

      ! Copy all atoms from system geometry
      full_system%element_numbers = sys_geom%element_numbers
      full_system%coordinates = sys_geom%coordinates

      ! Set charge and multiplicity from system
      full_system%charge = sys_geom%charge
      full_system%multiplicity = sys_geom%multiplicity
      call full_system%compute_nelec()

      ! Validate geometry (check for spatially overlapping atoms)
      call check_duplicate_atoms(full_system, error)
      if (error%has_error()) then
         call logger%error(error%get_full_trace())
         error stop "Overlapping atoms in unfragmented system"
      end if

      ! Process the full system
      call do_fragment_work(0_int64, result, config%method_config, phys_frag=full_system, calc_type=config%calc_type)

      ! Check for calculation errors
      if (result%has_error) then
         call logger%error("Unfragmented calculation failed: "//result%error%get_message())
         if (present(result_out)) then
            result_out = result
            return
         else
            error stop "Unfragmented calculation failed"
         end if
      end if

      call logger%info("============================================")
      call logger%info("Unfragmented calculation completed")
      block
         character(len=2048) :: result_line  ! Large buffer for Hessian matrix rows
         integer :: current_log_level, iatom, i, j
         real(dp) :: hess_norm

         write (result_line, '(a,f25.15)') "  Final energy: ", result%energy%total()
         call logger%info(trim(result_line))

         if (result%has_dipole) then
            write (result_line, '(a,3f15.8)') "  Dipole (e*Bohr): ", result%dipole
            call logger%info(trim(result_line))
            write (result_line, '(a,f15.8)') "  Dipole magnitude (Debye): ", norm2(result%dipole)*2.541746_dp
            call logger%info(trim(result_line))
         end if

         if (result%has_gradient) then
            write (result_line, '(a,f25.15)') "  Gradient norm: ", sqrt(sum(result%gradient**2))
            call logger%info(trim(result_line))

            ! Print full gradient if verbose and system is small
            call logger%configuration(level=current_log_level)
            if (current_log_level >= verbose_level .and. total_atoms < 100) then
               call logger%info(" ")
               call logger%info("Gradient (Hartree/Bohr):")
               do iatom = 1, total_atoms
                  write (result_line, '(a,i5,a,3f20.12)') "  Atom ", iatom, ": ", &
                     result%gradient(1, iatom), result%gradient(2, iatom), result%gradient(3, iatom)
                  call logger%info(trim(result_line))
               end do
               call logger%info(" ")
            end if
         end if

         if (result%has_hessian) then
            ! Compute Frobenius norm of Hessian
            hess_norm = sqrt(sum(result%hessian**2))
            write (result_line, '(a,f25.15)') "  Hessian Frobenius norm: ", hess_norm
            call logger%info(trim(result_line))

            ! Print full Hessian if verbose and system is small
            call logger%configuration(level=current_log_level)
            if (current_log_level >= verbose_level .and. total_atoms < 20) then
               call logger%info(" ")
               call logger%info("Hessian matrix (Hartree/Bohr^2):")
               do i = 1, 3*total_atoms
                  write (result_line, '(a,i5,a,999f15.8)') "  Row ", i, ": ", (result%hessian(i, j), j=1, 3*total_atoms)
                  call logger%info(trim(result_line))
               end do
               call logger%info(" ")
            end if

            ! Compute and print vibrational analysis
            block
               real(dp), allocatable :: frequencies(:), eigenvalues(:), projected_hessian(:, :)
               real(dp), allocatable :: reduced_masses(:), force_constants(:)
               real(dp), allocatable :: cart_disp(:, :), fc_mdyne(:), ir_intensities(:)
               integer :: ii, jj

               ! First get projected Hessian for verbose output
               call logger%info("  Computing vibrational analysis (projecting trans/rot modes)...")
               call compute_vibrational_frequencies(result%hessian, sys_geom%element_numbers, frequencies, eigenvalues, &
                                                    coordinates=sys_geom%coordinates, project_trans_rot=.true., &
                                                    projected_hessian_out=projected_hessian)

               ! Print projected mass-weighted Hessian if verbose and small system
               if (current_log_level >= verbose_level .and. total_atoms < 20) then
                  if (allocated(projected_hessian)) then
                     call logger%info(" ")
                     call logger%info("Mass-weighted Hessian after trans/rot projection (a.u.):")
                     do ii = 1, 3*total_atoms
                        write (result_line, '(a,i5,a,999f15.8)') "  Row ", ii, ": ", &
                           (projected_hessian(ii, jj), jj=1, 3*total_atoms)
                        call logger%info(trim(result_line))
                     end do
                     call logger%info(" ")
                  end if
               end if

               ! Compute full vibrational analysis and print (with IR intensities if available)
               if (result%has_dipole_derivatives) then
                  call compute_vibrational_analysis(result%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, &
                                                    dipole_derivatives=result%dipole_derivatives, &
                                                    ir_intensities=ir_intensities)
               else
                  call compute_vibrational_analysis(result%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)
               end if

               if (allocated(frequencies)) then
                  ! Compute thermochemistry for JSON output
                  block
                     type(thermochemistry_result_t) :: thermo_result
                     integer :: n_modes, n_at

                     n_at = size(sys_geom%element_numbers)
                     n_modes = size(frequencies)

                     call compute_thermochemistry(sys_geom%coordinates, sys_geom%element_numbers, &
                                                  frequencies, n_at, n_modes, thermo_result, &
                                                 temperature=config%hessian%temperature, pressure=config%hessian%pressure)

                     ! Print vibrational analysis to log
                     if (allocated(ir_intensities)) then
                        call print_vibrational_analysis(frequencies, reduced_masses, force_constants, &
                                                        cart_disp, sys_geom%element_numbers, &
                                                        force_constants_mdyne=fc_mdyne, &
                                                        ir_intensities=ir_intensities, &
                                                        coordinates=sys_geom%coordinates, &
                                                        electronic_energy=result%energy%total(), &
                                                 temperature=config%hessian%temperature, pressure=config%hessian%pressure)
                     else
                        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=result%energy%total(), &
                                                 temperature=config%hessian%temperature, pressure=config%hessian%pressure)
                     end if

                     ! Populate json_data if present (for centralized JSON output)
                     if (present(json_data)) then
                        json_data%output_mode = OUTPUT_MODE_UNFRAGMENTED
                        json_data%total_energy = result%energy%total()
                        json_data%has_energy = result%has_energy
                        json_data%has_vibrational = .true.

                        ! Copy vibrational data
                        allocate (json_data%frequencies(n_modes))
                        allocate (json_data%reduced_masses(n_modes))
                        allocate (json_data%force_constants(n_modes))
                        json_data%frequencies = frequencies
                        json_data%reduced_masses = reduced_masses
                        json_data%force_constants = fc_mdyne
                        json_data%thermo = thermo_result

                        if (allocated(ir_intensities)) then
                           allocate (json_data%ir_intensities(n_modes))
                           json_data%ir_intensities = ir_intensities
                           json_data%has_ir_intensities = .true.
                        end if

                        ! Copy dipole if available
                        if (result%has_dipole) then
                           allocate (json_data%dipole(3))
                           json_data%dipole = result%dipole
                           json_data%has_dipole = .true.
                        end if

                        ! Copy gradient if available
                        if (result%has_gradient) then
                           allocate (json_data%gradient(3, total_atoms))
                           json_data%gradient = result%gradient
                           json_data%has_gradient = .true.
                        end if

                        ! Copy hessian if available
                        if (result%has_hessian) then
                           allocate (json_data%hessian(3*total_atoms, 3*total_atoms))
                           json_data%hessian = result%hessian
                           json_data%has_hessian = .true.
                        end if
                     end if

                     if (allocated(ir_intensities)) deallocate (ir_intensities)
                  end block
                  deallocate (frequencies, reduced_masses, force_constants, cart_disp, fc_mdyne)
               end if

               if (allocated(eigenvalues)) deallocate (eigenvalues)
               if (allocated(projected_hessian)) deallocate (projected_hessian)
            end block
         end if
      end block
      call logger%info("============================================")

      ! Return result to caller or handle json_data
      if (present(result_out)) then
         ! Transfer result to output (for dynamics/optimization)
         result_out = result
      else
         ! Populate json_data for non-Hessian case if present
         ! (Hessian case already handled above in the vibrational block)
         if (present(json_data) .and. .not. result%has_hessian) then
            json_data%output_mode = OUTPUT_MODE_UNFRAGMENTED
            json_data%total_energy = result%energy%total()
            json_data%has_energy = result%has_energy

            if (result%has_dipole) then
               allocate (json_data%dipole(3))
               json_data%dipole = result%dipole
               json_data%has_dipole = .true.
            end if

            if (result%has_gradient) then
               allocate (json_data%gradient(3, total_atoms))
               json_data%gradient = result%gradient
               json_data%has_gradient = .true.
            end if
         end if
         call result%destroy()
      end if

   end subroutine unfragmented_calculation