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

Add Schwenke's gas phase H2O analytical potential #166

Merged
merged 16 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .fprettify.rc
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ enable-decl=True
disable-fypp=True

case=[1,1,1,2]
exclude=[random.F90,fftw3.F90,force_cp2k.F90]
exclude=[random.F90,fftw3.F90,force_cp2k.F90, h2o_schwenke.f]
11 changes: 5 additions & 6 deletions .github/workflows/gfortran.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,17 @@ env:
jobs:

format:
name: Format check
runs-on: ubuntu-20.04
strategy:
fail-fast: false
name: Code format check
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
fetch-depth: 2
python-version: '3.11'

- name: Install fprettify dependencies
run: pip install --user configargparse
run: pip install configargparse

- name: Run fprettify
run: |
Expand Down
4 changes: 2 additions & 2 deletions autoformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
try:
import configargparse
except ImportError:
print("Could not find configargparse package")
print("Please install it e.g. via 'pip install --user configargparse")
print("ERROR: Could not find configargparse package")
print("Please install the package, e.g. 'pip install --user configargparse'")
sys.exit(1)

if len(sys.argv) == 1:
Expand Down
493 changes: 493 additions & 0 deletions h2o_schwenke_orig.f

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
F_OBJS := constants.o fortran_interfaces.o error.o modules.o mpi_wrapper.o files.o utils.o io.o random.o arrays.o qmmm.o fftw_interface.o \
shake.o nosehoover.o gle.o transform.o potentials.o force_spline.o estimators.o ekin.o vinit.o plumed.o \
remd.o force_bound.o water.o force_cp2k.o sh_integ.o surfacehop.o landau_zener.o\
remd.o force_bound.o water.o h2o_schwenke.o force_h2o.o force_cp2k.o sh_integ.o surfacehop.o landau_zener.o\
force_mm.o tera_mpi_api.o force_abin.o force_tcpb.o force_tera.o force_terash.o en_restraint.o analyze_ext_template.o geom_analysis.o analysis.o \
minimizer.o mdstep.o forces.o cmdline.o init.o

Expand All @@ -27,5 +27,8 @@ clean:
%.o: %.F90
$(FC) $(FFLAGS) $(DFLAGS) -c $<

%.o: %.f
$(FC) $(FFLAGS) $(DFLAGS) -c $<

%.o: %.cpp
$(CXX) $(CXXFLAGS) $(DFLAGS) -c $<
4 changes: 2 additions & 2 deletions src/force_abin.F90
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
! The basic workflow is very simple:
! 1. ABIN writes current geometry into file geom.dat
! in a XYZ format without the header.
! 2. ABIN launches the shell script POT/r.pot
! 2. ABIN launches the shell script <POT>/r.<pot>
! 3. The shellscript does a few things:
! i) Takes the input geometry and prepares the input file
! ii) Launches the QM program
Expand All @@ -15,7 +15,7 @@
!
! NOTE: We append bead index to every file name so that we can
! call the interface in parallel in PIMD simulations.
! NOTE: Interface for Surface Hopping is a bit more complicated,
! NOTE: The interface for Surface Hopping is a bit more complicated,
! see interfaces/MOLPRO-SH/r.molpro-sh
module mod_shell_interface_private
use mod_const, only: DP, ANG
Expand Down
114 changes: 114 additions & 0 deletions src/force_h2o.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
! Interface to analytical H2O (single water molecule) potentials.
! This is invoked via pot='_h2o_', and the potential is selected via
! h2opot='schwenke'
module mod_force_h2o
use mod_const, only: DP
use mod_files, only: stdout, stderr
use mod_error, only: fatal_error
use mod_interfaces, only: h2o_pot_schwenke
implicit none
private
public :: initialize_h2o_pot, force_h2o, h2opot
character(len=20) :: h2opot = 'schwenke'
save
contains

! Perform some basic validation
subroutine initialize_h2o_pot(natom, atom_names)
integer, intent(in) :: natom
character(len=2), intent(in) :: atom_names(natom)

if (natom /= 3) then
call fatal_error(__FILE__, __LINE__, "This is not a water molecule!")

Check warning on line 22 in src/force_h2o.F90

View check run for this annotation

Codecov / codecov/patch

src/force_h2o.F90#L22

Added line #L22 was not covered by tests
end if

if (atom_names(1) /= 'O' .or. atom_names(2) /= 'H' .or. atom_names(3) /= 'H') then
write (stderr, *) 'ERROR: Bad element type.'
write (stderr, *) 'Water atoms must be ordered as "O H H"'
call fatal_error(__FILE__, __LINE__, "This is not a water molecule!")

Check warning on line 28 in src/force_h2o.F90

View check run for this annotation

Codecov / codecov/patch

src/force_h2o.F90#L26-L28

Added lines #L26 - L28 were not covered by tests
end if
end subroutine initialize_h2o_pot

! Compute internal coordinates from cartesians
! OH distances in bohrs, HOH angle in radians
subroutine get_internal_coords(x, y, z, iw, rOH1, rOH2, aHOH_rad)
use mod_const, only: PI
use mod_utils, only: get_distance, get_angle
real(DP), intent(in) :: x(:, :), y(:, :), z(:, :)
integer, intent(in) :: iw
real(DP), intent(out) :: rOH1, rOH2, aHOH_rad
real(DP) :: aHOH_deg

rOH1 = get_distance(x, y, z, 1, 2, iw)
rOH2 = get_distance(x, y, z, 1, 3, iw)
aHOH_deg = get_angle(x, y, z, 2, 1, 3, iw)
aHOH_rad = aHOH_deg * PI / 180.0D0
end subroutine get_internal_coords

! This is just a wrapper function that selects the H2O potential
! based on user input. For now only h2opot="schwenke" is supported
subroutine force_h2o(x, y, z, fx, fy, fz, eclas, natom, nbeads)
real(DP), intent(in) :: x(:, :), y(:, :), z(:, :)
real(DP), intent(inout) :: fx(:, :), fy(:, :), fz(:, :)
real(DP), intent(inout) :: eclas
integer, intent(in) :: natom, nbeads

! TODO: Use function pointers to select the potential and pass it down
if (h2opot == 'schwenke') then
call force_h2o_schwenke(x, y, z, fx, fy, fz, eclas, natom, nbeads)
else
call fatal_error(__FILE__, __LINE__, 'Potential '//trim(h2opot)//' not implemented')

Check warning on line 60 in src/force_h2o.F90

View check run for this annotation

Codecov / codecov/patch

src/force_h2o.F90#L60

Added line #L60 was not covered by tests
end if
end subroutine force_h2o

Check warning on line 62 in src/force_h2o.F90

View check run for this annotation

Codecov / codecov/patch

src/force_h2o.F90#L62

Added line #L62 was not covered by tests

subroutine force_h2o_schwenke(x, y, z, fx, fy, fz, Eclas, natom, nbeads)
real(DP), intent(in) :: x(:, :), y(:, :), z(:, :)
real(DP), intent(inout) :: fx(:, :), fy(:, :), fz(:, :)
real(DP), intent(inout) :: eclas
integer, intent(in) :: natom, nbeads
! Internal water coordinates
real(DP) :: rOH1, rOH2, aHOH_rad
real(DP) :: rij(nbeads, 3)
real(DP) :: Epot(nbeads)
integer :: iw

! The H2O potentials are evaluated in internal coordinates, but ABIN works in cartesians
do iw = 1, nbeads
call get_internal_coords(x, y, z, iw, rOH1, rOH2, aHOH_rad)
rij(iw, 1) = rOH1
rij(iw, 2) = rOH2
rij(iw, 3) = aHOH_rad
end do

! Calculated the potential for all PI beads at once
call h2o_pot_schwenke(rij, Epot, nbeads)
! For Path Integrals, the final energy of the PI necklace
! is an average over all beads.
! TODO: Forces need to be appropriately scaled as well!
do iw = 1, nbeads
Eclas = Eclas + Epot(iw)
end do
Eclas = Eclas / nbeads

call numerical_forces(x, y, z, fx, fy, fz, Epot, natom, nbeads)

end subroutine force_h2o_schwenke

Check warning on line 95 in src/force_h2o.F90

View check run for this annotation

Codecov / codecov/patch

src/force_h2o.F90#L95

Added line #L95 was not covered by tests

! TODO: Implement numerical forces generally for all potentials
! For now, they can be implemented here and hardcoded for a specific H2O potential
subroutine numerical_forces(x, y, z, Epot, fx, fy, fz, natom, nbeads)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mbarnfield63 Here's where you can start with your implementation.
Ultimately we'll want to have the implementation of numerical forces generalized and in a separate module, but that's not important at this stage.

real(DP), intent(in) :: x(natom, nbeads)
real(DP), intent(in) :: y(natom, nbeads)
real(DP), intent(in) :: z(natom, nbeads)
real(DP), intent(inout) :: fx(natom, nbeads)
real(DP), intent(inout) :: fy(natom, nbeads)
real(DP), intent(inout) :: fz(natom, nbeads)
! This is the energy for the currrent geometry that has already been calculated
real(DP), intent(in) :: Epot(nbeads)
integer, intent(in) :: natom, nbeads

! Need to implement numerical forces first
call fatal_error(__FILE__, __LINE__, 'Numerical forces not yet implemented!')
end subroutine numerical_forces

Check warning on line 112 in src/force_h2o.F90

View check run for this annotation

Codecov / codecov/patch

src/force_h2o.F90#L112

Added line #L112 was not covered by tests

end module mod_force_h2o
3 changes: 3 additions & 0 deletions src/forces.F90
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ subroutine force_wrapper(x, y, z, fx, fy, fz, e_pot, chpot, walkmax)
use mod_const, only: DP
use mod_general, only: natom, ipimd
use mod_water, only: watpot
use mod_force_h2o, only: force_h2o
use mod_force_mm, only: force_mm
use mod_sbc, only: force_sbc, isbc
use mod_plumed, only: iplumed, force_plumed
Expand Down Expand Up @@ -155,6 +156,8 @@ subroutine force_wrapper(x, y, z, fx, fy, fz, e_pot, chpot, walkmax)
call force_mm(x, y, z, fx, fy, fz, eclas, walkmax)
case ("_mmwater_")
call force_water(x, y, z, fx, fy, fz, eclas, natom, walkmax, watpot)
case ("_h2o_")
call force_h2o(x, y, z, fx, fy, fz, eclas, natom, walkmax)
case ("_splined_grid_")
! Only 1D spline grid supported at the moment
call force_splined_grid(x, fx, eclas, walkmax)
Expand Down
8 changes: 8 additions & 0 deletions src/fortran_interfaces.F90
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ function usleep(useconds) bind(c, name='usleep')
integer(kind=C_INT) :: usleep
end function usleep

! Returns a potential energy of a water molecule
! using Schwenke potential, see h2o_schwenke.f
subroutine h2o_pot_schwenke(rij, v, n)
import :: DP
integer, intent(in) :: n
real(DP) :: rij(n, 3), v(n)
end subroutine h2o_pot_schwenke

end interface

end module mod_interfaces
Loading
Loading