Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implemented -bhess option in xtb thermo submodule #1004

Merged
merged 13 commits into from
Sep 11, 2024
8 changes: 8 additions & 0 deletions src/hessian.F90
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ subroutine numhess( &
write(env%unit,'("writing file <",a,">.")') hname
call wrhess(n3,hss,hname)

! non mass weigthed biased Hessian in hsb
if (set%runtyp .eq. p_run_bhess) then
hname = 'hessian_sph'
write (env%unit, '(a)')
write (env%unit, '("writing file <",a,">.")') hname
call wrhess(n3, hsb, hname)
end if

! include masses
k=0
do i=1,n3
Expand Down
123 changes: 104 additions & 19 deletions src/prog/thermo.f90
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@

!> Thermodynamic functions and hessian post processing
module xtb_prog_thermo
use xtb_mctc_blas, only : mctc_gemv, mctc_dot
use xtb_mctc_accuracy, only : wp
use xtb_mctc_convert, only : autorcm, autoamu
use xtb_mctc_convert, only : autorcm, autoamu, amutoau
use xtb_mctc_filetypes, only : getFileType, hessType
use xtb_mctc_timings
use xtb_mctc_version, only : version, author, date
Expand All @@ -32,6 +33,7 @@ module xtb_prog_thermo
use xtb_propertyoutput, only : print_thermo
use xtb_splitparam, only : atmass
use xtb_setmod, only : set_thermo, set_symmetry
use xtb_freq_io, only : rdhess
implicit none
private

Expand Down Expand Up @@ -61,19 +63,23 @@ subroutine xtbThermo(env, argParser)
real(wp), allocatable :: freq(:), hessian(:, :)
real(wp) :: htot, gtot, zp
integer :: nFiles, ftype, hFormat, nimag
logical :: massWeighted
logical :: massWeighted, bhess

call parseArguments(env, argParser, hFormat, massWeighted)
call parseArguments(env, argParser, hFormat, massWeighted,bhess)

nFiles = argParser%countFiles()
if (nFiles == 0) then
call env%error("No input file given, so there is nothing to do", source)
call thermoHelp(env%unit)
end if
if (nFiles > 2) then
if (nFiles > 2 .and. .not. bhess) then
call env%error("Multiple input files present, aborting", source)
end if

if (nFiles > 3) then
call env%error("Multiple input files present, aborting", source)
end if

call env%checkpoint("Command line argument parsing failed")

call argParser%nextFile(file)
Expand Down Expand Up @@ -105,20 +111,24 @@ subroutine xtbThermo(env, argParser)
call reader%open(file)
call readHessian(env, mol, hessian, reader, format=hFormat)
call reader%close

if (.not.massWeighted) then
call massWeightHessian(hessian, mol%atmass)
end if

if (hFormat == hessType%dftbplus .or. hFormat == hessType%orca) then
call projectHessian(hessian, mol, .true., .true.)

if (bhess) then
call rescale_freq(env,argParser,mol,hessian,freq) ! frequencies have to be rescaled
else
if (.not.massWeighted) then
marcelmbn marked this conversation as resolved.
Show resolved Hide resolved
call massWeightHessian(hessian, mol%atmass)
end if

if (hFormat == hessType%dftbplus .or. hFormat == hessType%orca) then
call projectHessian(hessian, mol, .true., .true.)
end if

call diagHessian(env, hessian, freq)

call preigf(env%unit, freq, autorcm)

call env%checkpoint("Could not read hessian from '"//file//"'")
end if

call diagHessian(env, hessian, freq)

call preigf(env%unit, freq, autorcm)

call env%checkpoint("Could not read hessian from '"//file//"'")
else
freq(:) = -1.0_wp
end if
Expand Down Expand Up @@ -164,8 +174,75 @@ subroutine preigf(unit, freq, scale)
end subroutine preigf


! Remove the frequency shift caused by the bias RMSD employed in the SPH calculation:
subroutine rescale_freq(env,argParser,mol, hessian, freq)
real(wp), allocatable, intent(inout) :: freq(:), hessian(:, :)
marcelmbn marked this conversation as resolved.
Show resolved Hide resolved
real(wp), allocatable :: freq_sph(:), hessian_sph(:, :) ! biased hessian from SPH
real(wp), allocatable :: htb(:,:), v(:), fc_tmp(:), fc_tb(:), fc_bias(:), freq_scal(:)
real(wp) :: alp1, alp2 ! factors for SPH scaling
integer :: i,j,n3
type(TEnvironment), intent(inout) :: env
!> Commandline argument parser
type(TArgParser), intent(inout) :: argParser
type(TReader) :: reader
type(TMolecule) :: mol
character(len=:), allocatable :: file
integer :: hFormat
logical :: ex

n3= 3*mol%n
hFormat = 1 ! hessian_sph must stem from xtb SPH calculation!
call argParser%nextFile(file)
write(env%unit,'(a)') 'Reading hessian_sph file: '//file
write(env%unit,'(a)') 'Removing the frequency shift caused by the bias RMSD:'
allocate(freq_sph(n3))
if (allocated(file)) then
allocate(hessian_sph(n3,n3))
call reader%open(file)
call readHessian(env, mol, hessian_sph, reader, format=hFormat)
call reader%close
call massWeightHessian(hessian_sph, atmass) ! keep units similar to hessian.f90 routines in main program
call massWeightHessian(hessian, atmass) ! keep units similar to hessian.f90 routines in main program
htb=hessian-hessian_sph

call diagHessian(env, hessian, freq)

allocate(v(n3),fc_tmp(n3),freq_scal(n3),fc_tb(n3),fc_bias(n3))
! calculate fc_tb and fc_bias (same procedure as in hessian.f90)
alp1=1.27_wp
alp2=1.5d-4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid using fixed float point numbers?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is the whole function "copied" from the bhess workflow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just "copied" the function from the bhess workflow. Otherwise the bhess subroutine has to be also rewritten to avoid this "double code".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just use it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you highlight which lines of code from src/hessian.f90 are actually relevant and could be "recycled" here? So that we can think about putting these parts of the code into single functions that could be reused in this project. I'd strongly speak against implementing doubled code using fixed float point parameters (which is in itself already a bit of bad practice), if we can avoid it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it is mainly lines 397-416 from the updated hessian.F90 that could be reused here fairly easily.

do j=1,n3
v(1:n3) = hessian(1:n3,j) ! modes
call mctc_gemv(htb,v,fc_tmp)
fc_tb(j) = mctc_dot(v,fc_tmp)
call mctc_gemv(hessian_sph,v,fc_tmp)
fc_bias(j) = mctc_dot(v,fc_tmp)
if (abs(freq(j)).gt.1.0d-6) then
freq_scal(j) = sqrt( (fc_tb(j)+alp2) / ( (fc_tb(j)+alp2) + alp1*fc_bias(j) ) )
if (fc_tb(j).lt.0.and.fc_bias(j).ne.0) then
freq_scal(j) = -sqrt( (abs(fc_tb(j))+alp2) / ( (abs(fc_tb(j))+alp2) + alp1*fc_bias(j) ) )
end if
else
freq_scal(j) = 1.0_wp
end if
end do

! scale frequencies and convert now to atomic units
do j=1,n3
freq(j) = freq(j) * freq_scal(j)/sqrt(amutoau)
end do

call preigf(env%unit, freq, autorcm)
else
marcelmbn marked this conversation as resolved.
Show resolved Hide resolved
print*, "no hessian_sph file found, --bhess mode can not be used"
call terminate(1)
end if

end subroutine rescale_freq


!> Parse command line arguments
subroutine parseArguments(env, args, htype, massWeighted)
subroutine parseArguments(env, args, htype, massWeighted,bhess)

!> Name of error producer
character(len=*), parameter :: source = "prog_thermo_parseArguments"
Expand All @@ -182,11 +259,15 @@ subroutine parseArguments(env, args, htype, massWeighted)
!> Hessian is already mass weighted
logical, intent(out) :: massWeighted

!> Hessian stems from a biased SPH calculation
logical, intent(out) :: bhess

integer :: nFlags
character(len=:), allocatable :: flag, sec

htype = hessType%tmol
massWeighted = .false.
bhess = .false.

nFlags = args%countFlags()
call args%nextFlag(flag)
Expand Down Expand Up @@ -253,6 +334,8 @@ subroutine parseArguments(env, args, htype, massWeighted)
else
call env%error("Temperature in K is missing", source)
end if
case('--bhess')
bhess = .true.

end select
call args%nextFlag(flag)
Expand Down Expand Up @@ -316,6 +399,9 @@ subroutine thermoHelp(unit)
"",&
" --orca Read an Orca Hessian file",&
"",&
" --bhess Read in an <hessian_sph> file from a previous xTB SPH calculation ",&
" and scale frequencies accordingly",&
"",&
"Output Conventions:",&
"",&
"total energies are given in atomic units (Eh), frequencies in reciprocal cm",&
Expand All @@ -324,5 +410,4 @@ subroutine thermoHelp(unit)
""
end subroutine thermoHelp


end module xtb_prog_thermo
Loading