angle_potential Subroutine

public subroutine angle_potential(bds, V)

Uses

  • proc~~angle_potential~~UsesGraph proc~angle_potential angle_potential module~mod_constants mod_constants proc~angle_potential->module~mod_constants iso_c_binding iso_c_binding module~mod_constants->iso_c_binding

Compute angle-bending terms of the potential energy function.
Simple angle terms are computed according to the formula:
Out-of plane angle are more complex. First, central atom has to be a trigonal center, the other two atoms together with the auxliary atom (that is the remaining one connected to the trigonal center) define the projection plane. During the first run the auxiliary atom is found and saved. Then, the trigonal center is projected on the plane defined by the other three atoms, and the angle is the one defined by the projection (which is the vertex, and the other two atoms -- the auxiliary is excluded). Then the same formula used for simple angle terms is used. Trigonal center Normal vector of the projection plane

Arguments

Type IntentOptional Attributes Name
type(ommp_bonded_type), intent(in) :: bds
real(kind=rp), intent(inout) :: V

Bond potential, result will be added to V


Called by

proc~~angle_potential~~CalledByGraph proc~angle_potential angle_potential proc~ommp_get_angle_energy ommp_get_angle_energy proc~ommp_get_angle_energy->proc~angle_potential proc~ommp_get_full_bnd_energy ommp_get_full_bnd_energy proc~ommp_get_full_bnd_energy->proc~angle_potential proc~c_ommp_get_angle_energy C_ommp_get_angle_energy proc~c_ommp_get_angle_energy->proc~ommp_get_angle_energy proc~c_ommp_get_full_bnd_energy C_ommp_get_full_bnd_energy proc~c_ommp_get_full_bnd_energy->proc~ommp_get_full_bnd_energy proc~ommp_get_full_energy ommp_get_full_energy proc~ommp_get_full_energy->proc~ommp_get_full_bnd_energy proc~c_ommp_get_full_energy C_ommp_get_full_energy proc~c_ommp_get_full_energy->proc~ommp_get_full_energy

Contents

Source Code


Source Code

    subroutine angle_potential(bds, V)
        !! Compute angle-bending terms of the potential energy function.   
        !! Simple angle terms are computed according to the formula:
        !! \[U_{angle} = \sum_i k_i \Delta \theta_i^2 \large(1 +  
        !!  \sum_{j=1}^4 k^{(j+2)} \Delta \theta_i^j \large)\]
        !! \[\Delta \theta_i = \theta_i - \theta^{(eq)}_i\]    
        !! Out-of plane angle are more complex. First, central atom has to be
        !! a trigonal center, the other two atoms together with the auxliary 
        !! atom (that is the remaining one connected to the trigonal center) 
        !! define the projection plane. During the first run the auxiliary atom
        !! is found and saved.
        !! Then, the trigonal center is projected on the plane defined by the 
        !! other three atoms, and the angle is the one defined by the projection
        !! (which is the vertex, and the other two atoms -- the auxiliary is
        !! excluded). Then the same formula used for simple angle terms is used.
        use mod_constants, only: eps_rp
        implicit none

        type(ommp_bonded_type), intent(in) :: bds
        ! Bonded potential data structure
        real(rp), intent(inout) :: V
        !! Bond potential, result will be added to V
        
        integer(ip) :: i
        real(rp) :: l1, l2, dr1(3), dr2(3), thet, d_theta
        real(rp), dimension(3) :: v_dist, plv1, plv2, pln, a, b, c, prj_b, aux

        if(.not. bds%use_angle) return
        
        !$omp parallel do default(shared) schedule(static) reduction(+:V) &
        !$omp private(i,dr1,dr2,l1,l2,thet,d_theta,a,b,c,aux,plv1,plv2,pln,v_dist,prj_b) 
        do i=1, bds%nangle
            if(abs(bds%kangle(i)) < eps_rp) cycle
            if(bds%anglety(i) == OMMP_ANG_SIMPLE .or. &
               bds%anglety(i) == OMMP_ANG_H0 .or. &
               bds%anglety(i) == OMMP_ANG_H1 .or. &
               bds%anglety(i) == OMMP_ANG_H2) then
                dr1 = bds%top%cmm(:, bds%angleat(1,i)) - bds%top%cmm(:, bds%angleat(2,i))
                dr2 = bds%top%cmm(:, bds%angleat(3,i)) - bds%top%cmm(:, bds%angleat(2,i))
                l1 = sqrt(dot_product(dr1, dr1))
                l2 = sqrt(dot_product(dr2, dr2))

                thet = acos(dot_product(dr1, dr2)/(l1*l2))
                
                d_theta = thet-bds%eqangle(i) 
                
                V = V + bds%kangle(i) * d_theta**2 * (1.0 + bds%angle_cubic*d_theta &
                    + bds%angle_quartic*d_theta**2 + bds%angle_pentic*d_theta**3 &
                    + bds%angle_sextic*d_theta**4)

            else if(bds%anglety(i) == OMMP_ANG_INPLANE .or. &
                    bds%anglety(i) == OMMP_ANG_INPLANE_H0 .or. &
                    bds%anglety(i) == OMMP_ANG_INPLANE_H1) then
                
                a = bds%top%cmm(:, bds%angleat(1,i))
                b = bds%top%cmm(:, bds%angleat(2,i)) !! Trigonal center
                c = bds%top%cmm(:, bds%angleat(3,i))

                aux = bds%top%cmm(:, bds%angauxat(i))
                plv1 = a - aux
                plv2 = c - aux
                pln(1) = plv1(2)*plv2(3) - plv1(3)*plv2(2)
                pln(2) = plv1(3)*plv2(1) - plv1(1)*plv2(3)
                pln(3) = plv1(1)*plv2(2) - plv1(2)*plv2(1)
                !! Normal vector of the projection plane
                pln = pln / sqrt(dot_product(pln, pln))

                v_dist = b - aux
                prj_b = b - dot_product(v_dist, pln) * pln 

                dr1 = bds%top%cmm(:, bds%angleat(1,i)) - prj_b
                dr2 = bds%top%cmm(:, bds%angleat(3,i)) - prj_b
                l1 = sqrt(dot_product(dr1, dr1))
                l2 = sqrt(dot_product(dr2, dr2))

                thet = acos(dot_product(dr1, dr2)/(l1*l2))
                
                d_theta = thet-bds%eqangle(i) 
                
                V = V + bds%kangle(i) * d_theta**2 * (1.0 + bds%angle_cubic*d_theta &
                    + bds%angle_quartic*d_theta**2 + bds%angle_pentic*d_theta**3 &
                    + bds%angle_sextic*d_theta**4)
            end if
        end do
    end subroutine angle_potential