Compute IR intensities from dipole derivatives and normal modes.
IR intensities are computed by transforming Cartesian dipole derivatives to normal mode coordinates and computing the squared magnitude.
For each normal mode i: trdip(k) = Σ_j dipd(k,j) * L(j,i) * 1/√m_j IR(i) = AU_TO_KMMOL * (trdip(1)² + trdip(2)² + trdip(3)²)
where: dipd(k,j) = ∂μ_k/∂x_j (Cartesian dipole derivative) L(j,i) = mass-weighted eigenvector component m_j = atomic mass for coordinate j
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | dipole_derivatives(:,:) |
Cartesian dipole derivatives (3, 3*N) in atomic units |
||
| real(kind=dp), | intent(in) | :: | eigenvectors(:,:) |
Mass-weighted eigenvectors from Hessian diagonalization (3N x 3N) |
||
| integer, | intent(in) | :: | element_numbers(:) |
Atomic numbers for each atom (N atoms) |
||
| real(kind=dp), | intent(out), | allocatable | :: | ir_intensities(:) |
IR intensities in km/mol (one per mode) |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | i | ||||
| integer, | private | :: | iatom | ||||
| real(kind=dp), | private | :: | inv_sqrt_mass | ||||
| integer, | private | :: | j | ||||
| integer, | private | :: | k | ||||
| real(kind=dp), | private | :: | mass | ||||
| integer, | private | :: | n_atoms | ||||
| integer, | private | :: | n_coords | ||||
| real(kind=dp), | private | :: | trdip(3) |
subroutine compute_ir_intensities(dipole_derivatives, eigenvectors, element_numbers, ir_intensities) !! Compute IR intensities from dipole derivatives and normal modes. !! !! IR intensities are computed by transforming Cartesian dipole derivatives !! to normal mode coordinates and computing the squared magnitude. !! !! For each normal mode i: !! trdip(k) = Σ_j dipd(k,j) * L(j,i) * 1/√m_j !! IR(i) = AU_TO_KMMOL * (trdip(1)² + trdip(2)² + trdip(3)²) !! !! where: !! dipd(k,j) = ∂μ_k/∂x_j (Cartesian dipole derivative) !! L(j,i) = mass-weighted eigenvector component !! m_j = atomic mass for coordinate j !! real(dp), intent(in) :: dipole_derivatives(:, :) !! Cartesian dipole derivatives (3, 3*N) in atomic units real(dp), intent(in) :: eigenvectors(:, :) !! Mass-weighted eigenvectors from Hessian diagonalization (3*N x 3*N) integer, intent(in) :: element_numbers(:) !! Atomic numbers for each atom (N atoms) real(dp), allocatable, intent(out) :: ir_intensities(:) !! IR intensities in km/mol (one per mode) integer :: n_atoms, n_coords, iatom, i, j, k real(dp) :: mass, inv_sqrt_mass, trdip(3) n_atoms = size(element_numbers) n_coords = 3*n_atoms allocate (ir_intensities(n_coords)) ! For each normal mode i do i = 1, n_coords trdip = 0.0_dp ! Transform dipole derivative from Cartesian to normal mode coordinates ! trdip(k) = Σ_j dipd(k,j) * L(j,i) * amass_au(j) ! where amass_au(j) = 1/√(m_j in atomic units) = 1/√(m_amu * AMU_TO_AU) ! This matches xtb's formula in hessian.F90 lines 526-535 do j = 1, n_coords iatom = (j - 1)/3 + 1 mass = element_mass(element_numbers(iatom)) ! Convert mass to atomic units (electron masses) before taking sqrt inv_sqrt_mass = 1.0_dp/sqrt(mass*AMU_TO_AU) do k = 1, 3 ! x, y, z components of dipole trdip(k) = trdip(k) + dipole_derivatives(k, j)*eigenvectors(j, i)*inv_sqrt_mass end do end do ! IR intensity = |dμ/dQ|² * conversion factor ir_intensities(i) = AU_TO_KMMOL*(trdip(1)**2 + trdip(2)**2 + trdip(3)**2) end do end subroutine compute_ir_intensities