compute_cartesian_displacements Subroutine

public subroutine compute_cartesian_displacements(eigenvectors, element_numbers, cartesian_displacements, normalize_max)

Convert mass-weighted eigenvectors to Cartesian displacements.

The Cartesian displacement for coordinate i in mode k is: x_{i,k} = L_mw_{i,k} / √(m_i)

The output can be normalized in two ways: - normalize_max=.true. (default): normalize so max|x| = 1 for each mode (Gaussian convention) - normalize_max=.false.: normalize so Σ_i x²_{i,k} = 1

Arguments

Type IntentOptional Attributes Name
real(kind=dp), intent(in) :: eigenvectors(:,:)

Mass-weighted eigenvectors (3N x 3N)

integer, intent(in) :: element_numbers(:)

Atomic numbers for each atom (N atoms)

real(kind=dp), intent(out), allocatable :: cartesian_displacements(:,:)

Cartesian displacement vectors (3N x 3N), columns are modes

logical, intent(in), optional :: normalize_max

If true, normalize so max displacement = 1 (default: true)


Calls

proc~~compute_cartesian_displacements~~CallsGraph proc~compute_cartesian_displacements compute_cartesian_displacements proc~element_mass element_mass proc~compute_cartesian_displacements->proc~element_mass

Called by

proc~~compute_cartesian_displacements~~CalledByGraph proc~compute_cartesian_displacements compute_cartesian_displacements proc~compute_vibrational_analysis compute_vibrational_analysis proc~compute_vibrational_analysis->proc~compute_cartesian_displacements proc~compute_gmbe compute_gmbe proc~compute_gmbe->proc~compute_vibrational_analysis proc~compute_mbe compute_mbe proc~compute_mbe->proc~compute_vibrational_analysis proc~gmbe_pie_coordinator gmbe_pie_coordinator proc~gmbe_pie_coordinator->proc~compute_vibrational_analysis proc~hessian_coordinator hessian_coordinator proc~hessian_coordinator->proc~compute_vibrational_analysis proc~serial_gmbe_pie_processor serial_gmbe_pie_processor proc~serial_gmbe_pie_processor->proc~compute_vibrational_analysis proc~unfragmented_calculation unfragmented_calculation proc~unfragmented_calculation->proc~compute_vibrational_analysis interface~hessian_coordinator hessian_coordinator interface~hessian_coordinator->proc~hessian_coordinator interface~unfragmented_calculation unfragmented_calculation interface~unfragmented_calculation->proc~unfragmented_calculation proc~global_coordinator global_coordinator proc~global_coordinator->proc~compute_mbe proc~gmbe_run_distributed gmbe_context_t%gmbe_run_distributed proc~gmbe_run_distributed->proc~gmbe_pie_coordinator proc~gmbe_run_serial gmbe_context_t%gmbe_run_serial proc~gmbe_run_serial->proc~serial_gmbe_pie_processor proc~serial_fragment_processor serial_fragment_processor proc~serial_fragment_processor->proc~compute_mbe interface~global_coordinator global_coordinator interface~global_coordinator->proc~global_coordinator interface~serial_fragment_processor serial_fragment_processor interface~serial_fragment_processor->proc~serial_fragment_processor proc~distributed_unfragmented_hessian distributed_unfragmented_hessian proc~distributed_unfragmented_hessian->interface~hessian_coordinator proc~run_unfragmented_calculation run_unfragmented_calculation proc~run_unfragmented_calculation->interface~unfragmented_calculation interface~distributed_unfragmented_hessian distributed_unfragmented_hessian interface~distributed_unfragmented_hessian->proc~distributed_unfragmented_hessian proc~mbe_run_distributed mbe_context_t%mbe_run_distributed proc~mbe_run_distributed->interface~global_coordinator proc~mbe_run_serial mbe_context_t%mbe_run_serial proc~mbe_run_serial->interface~serial_fragment_processor proc~run_calculation run_calculation proc~run_calculation->proc~run_unfragmented_calculation

Variables

Type Visibility Attributes Name Initial
integer, private :: iatom
integer, private :: icoord
integer, private :: idx
real(kind=dp), private :: inv_sqrt_mass
integer, private :: k
real(kind=dp), private :: mass
real(kind=dp), private :: max_disp
integer, private :: n_atoms
integer, private :: n_coords
real(kind=dp), private :: norm
logical, private :: use_max_norm

Source Code

   subroutine compute_cartesian_displacements(eigenvectors, element_numbers, &
                                              cartesian_displacements, normalize_max)
      !! Convert mass-weighted eigenvectors to Cartesian displacements.
      !!
      !! The Cartesian displacement for coordinate i in mode k is:
      !!   x_{i,k} = L_mw_{i,k} / √(m_i)
      !!
      !! The output can be normalized in two ways:
      !! - normalize_max=.true. (default): normalize so max|x| = 1 for each mode (Gaussian convention)
      !! - normalize_max=.false.: normalize so Σ_i x²_{i,k} = 1
      real(dp), intent(in) :: eigenvectors(:, :)
         !! Mass-weighted eigenvectors (3*N x 3*N)
      integer, intent(in) :: element_numbers(:)
         !! Atomic numbers for each atom (N atoms)
      real(dp), allocatable, intent(out) :: cartesian_displacements(:, :)
         !! Cartesian displacement vectors (3*N x 3*N), columns are modes
      logical, intent(in), optional :: normalize_max
         !! If true, normalize so max displacement = 1 (default: true)

      integer :: n_atoms, n_coords, iatom, icoord, k, idx
      real(dp) :: mass, inv_sqrt_mass, norm, max_disp
      logical :: use_max_norm

      n_atoms = size(element_numbers)
      n_coords = 3*n_atoms

      use_max_norm = .true.
      if (present(normalize_max)) use_max_norm = normalize_max

      allocate (cartesian_displacements(n_coords, n_coords))

      ! Convert from mass-weighted to Cartesian: x = L_mw / √m
      do k = 1, n_coords
         do iatom = 1, n_atoms
            mass = element_mass(element_numbers(iatom))
            inv_sqrt_mass = 1.0_dp/sqrt(mass)
            do icoord = 1, 3
               idx = 3*(iatom - 1) + icoord
               cartesian_displacements(idx, k) = eigenvectors(idx, k)*inv_sqrt_mass
            end do
         end do
      end do

      ! Normalize each mode
      do k = 1, n_coords
         if (use_max_norm) then
            ! Gaussian convention: normalize so max |displacement| = 1
            max_disp = maxval(abs(cartesian_displacements(:, k)))
            if (max_disp > 1.0e-14_dp) then
               cartesian_displacements(:, k) = cartesian_displacements(:, k)/max_disp
            end if
         else
            ! Standard normalization: Σ_i x²_{i,k} = 1
            norm = sqrt(sum(cartesian_displacements(:, k)**2))
            if (norm > 1.0e-14_dp) then
               cartesian_displacements(:, k) = cartesian_displacements(:, k)/norm
            end if
         end if
      end do

   end subroutine compute_cartesian_displacements