ESPResSo 3.2.0-64-g5125f6e-git
Extensible Simulation Package for Soft Matter Research
angle.h
Go to the documentation of this file.
00001 /*
00002   Copyright (C) 2010,2011,2012,2013 The ESPResSo project
00003   Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 
00004     Max-Planck-Institute for Polymer Research, Theory Group
00005   
00006   This file is part of ESPResSo.
00007   
00008   ESPResSo is free software: you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation, either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   ESPResSo is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
00020 */
00021 #ifndef ANGLE_H
00022 #define ANGLE_H
00023 /** \file angle.h
00024  *  Routines to calculate the angle energy or/and and force 
00025  *  for a particle triple.
00026  *  \ref forces.c
00027 */
00028 
00029 #include "utils.h"
00030 #include "interaction_data.h"
00031 #include "particle_data.h"
00032 
00033 #ifdef BOND_ANGLE_OLD
00034 #include "grid.h"
00035 
00036 /** set parameters for the angle potential.
00037 
00038     \todo The type of the angle potential
00039     is chosen via config.h and cannot be changed at runtime.
00040 */
00041 int angle_set_params(int bond_type, double bend, double phi0);
00042 
00043 /************************************************************/
00044 
00045 /** Computes the three body angle interaction force and adds this
00046     force to the particle forces (see \ref tclcommand_inter). 
00047     @param p_mid     Pointer to second/middle particle.
00048     @param p_left    Pointer to first/left particle.
00049     @param p_right   Pointer to third/right particle.
00050     @param iaparams  bond type number of the angle interaction (see \ref tclcommand_inter).
00051     @param force1 returns force of particle 1
00052     @param force2 returns force of particle 2
00053     @return 0
00054 */
00055 MDINLINE int calc_angle_force(Particle *p_mid, Particle *p_left, Particle *p_right,
00056                               Bonded_ia_parameters *iaparams, double force1[3], double force2[3])
00057 {
00058   double cosine, vec1[3], vec2[3], d1i, d2i, dist2,  fac, f1=0.0, f2=0.0;
00059   int j;
00060 
00061   cosine=0.0;
00062   /* vector from p_left to p_mid */
00063   get_mi_vector(vec1, p_mid->r.p, p_left->r.p);
00064   dist2 = sqrlen(vec1);
00065   d1i = 1.0 / sqrt(dist2);
00066   for(j=0;j<3;j++) vec1[j] *= d1i;
00067   /* vector from p_mid to p_right */
00068   get_mi_vector(vec2, p_right->r.p, p_mid->r.p);
00069   dist2 = sqrlen(vec2);
00070   d2i = 1.0 / sqrt(dist2);
00071   for(j=0;j<3;j++) vec2[j] *= d2i;
00072   /* scalar produvt of vec1 and vec2 */
00073   cosine = scalar(vec1, vec2);
00074   fac    = iaparams->p.angle.bend;
00075 
00076 #ifdef BOND_ANGLE_HARMONIC
00077   {
00078     double phi,sinphi;
00079     if ( cosine >  TINY_COS_VALUE) cosine = TINY_COS_VALUE;
00080     if ( cosine < -TINY_COS_VALUE)  cosine = -TINY_COS_VALUE;
00081     phi =  acos(-cosine);
00082     sinphi = sin(phi);
00083     if ( sinphi < TINY_SIN_VALUE ) sinphi = TINY_SIN_VALUE;
00084     fac *= (phi - iaparams->p.angle.phi0)/sinphi;
00085   }
00086 #endif
00087 #ifdef BOND_ANGLE_COSINE
00088   if ( cosine >  TINY_COS_VALUE ) cosine = TINY_COS_VALUE;
00089   if ( cosine < -TINY_COS_VALUE)  cosine = -TINY_COS_VALUE;
00090   fac *= iaparams->p.angle.sin_phi0 * (cosine/sqrt(1-SQR(cosine))) + iaparams->p.angle.cos_phi0;
00091 #endif
00092 #ifdef BOND_ANGLE_COSSQUARE
00093   fac *= iaparams->p.angle.cos_phi0 + cosine;
00094 #endif
00095   for(j=0;j<3;j++) {
00096     f1               = fac * (cosine * vec1[j] - vec2[j]) * d1i;
00097     f2               = fac * (cosine * vec2[j] - vec1[j]) * d2i;
00098 
00099     force1[j] = (f1-f2);
00100     force2[j] = -f1;
00101   }
00102   return 0;
00103 }
00104 
00105 /* The force on each particle due to a three-body bonded potential
00106    is computed. */
00107 MDINLINE void calc_angle_3body_forces(Particle *p_mid, Particle *p_left,
00108               Particle *p_right, Bonded_ia_parameters *iaparams,
00109               double force1[3], double force2[3], double force3[3]) {
00110 
00111   int j;
00112   double pot_dep;
00113   double cos_phi;
00114   double sin_phi;
00115   double vec31[3];
00116   double vec21[3];
00117   double vec12[3]; // espresso convention
00118   double vec21_sqr;
00119   double vec31_sqr;
00120   double vec21_magn;
00121   double vec31_magn;
00122   double fj[3];
00123   double fk[3];
00124   double fac;
00125 
00126   get_mi_vector(vec12, p_mid->r.p, p_left->r.p);
00127   for(j = 0; j < 3; j++)
00128     vec21[j] = -vec12[j];
00129 
00130   get_mi_vector(vec31, p_right->r.p, p_mid->r.p);
00131   vec21_sqr = sqrlen(vec21);
00132   vec21_magn = sqrt(vec21_sqr);
00133   vec31_sqr = sqrlen(vec31);
00134   vec31_magn = sqrt(vec31_sqr);
00135   cos_phi = scalar(vec21, vec31) / (vec21_magn * vec31_magn);
00136   sin_phi = sqrt(1.0 - SQR(cos_phi));
00137 
00138   /* uncomment this block if interested in the angle 
00139   if(cos_phi < -1.0) cos_phi = -TINY_COS_VALUE;
00140   if(cos_phi >  1.0) cos_phi =  TINY_COS_VALUE; 
00141   phi = acos(cos_phi);
00142   */
00143 #ifdef BOND_ANGLE_HARMONIC
00144   {
00145     double K, phi, phi0;
00146     if(cos_phi < -1.0) cos_phi = -TINY_COS_VALUE;
00147     if(cos_phi >  1.0) cos_phi =  TINY_COS_VALUE;
00148     phi = acos(cos_phi);
00149 
00150     K = iaparams->p.angle.bend;
00151     phi0 = iaparams->p.angle.phi0;
00152 
00153     // potential dependent term [dU/dphi = K * (phi - phi0)]
00154     pot_dep = K * (phi - phi0);
00155   }
00156 #endif
00157 #ifdef BOND_ANGLE_COSINE
00158   {
00159     double K, sin_phi0, cos_phi0;
00160     K = iaparams->p.angle.bend;
00161     sin_phi0 = iaparams->p.angle.sin_phi0;
00162     cos_phi0 = iaparams->p.angle.cos_phi0;
00163 
00164     // potential dependent term [dU/dphi = K * sin(phi - phi0)]
00165     // trig identity: sin(a - b) = sin(a)cos(b) - cos(a)sin(b) 
00166     pot_dep = K * (sin_phi * cos_phi0 - cos_phi * sin_phi0);
00167   }
00168 #endif
00169 #ifdef BOND_ANGLE_COSSQUARE
00170   {
00171     double K, cos_phi0;
00172     K = iaparams->p.angle.bend;
00173     cos_phi0 = iaparams->p.angle.cos_phi0;
00174     
00175     // potential dependent term [dU/dphi = K * (sin_phi * cos_phi0 - cos_phi * sin_phi)]
00176     pot_dep = K * (sin_phi * cos_phi0 - cos_phi * sin_phi);
00177   }
00178 #endif
00179 
00180   fac = pot_dep / sin_phi;
00181 
00182   for(j = 0; j < 3; j++) {
00183     fj[j] = vec31[j] / (vec21_magn * vec31_magn) - cos_phi * vec21[j] / vec21_sqr;
00184     fk[j] = vec21[j] / (vec21_magn * vec31_magn) - cos_phi * vec31[j] / vec31_sqr;
00185   }
00186 
00187   // note that F1 = -(F2 + F3)
00188   for(j = 0; j < 3; j++) {
00189     force1[j] = force1[j] - fac * (fj[j] + fk[j]);
00190     force2[j] = force2[j] + fac * fj[j];
00191     force3[j] = force3[j] + fac * fk[j];
00192   }
00193 }
00194 
00195 
00196 /** Computes the three body angle interaction energy (see \ref tclcommand_inter, \ref tclcommand_analyze). 
00197     @param p_mid        Pointer to first particle.
00198     @param p_left        Pointer to second/middle particle.
00199     @param p_right        Pointer to third particle.
00200     @param iaparams  bond type number of the angle interaction (see \ref tclcommand_inter).
00201     @param _energy   return energy pointer.
00202     @return 0.
00203 */
00204 MDINLINE int angle_energy(Particle *p_mid, Particle *p_left, Particle *p_right,
00205                              Bonded_ia_parameters *iaparams, double *_energy)
00206 {
00207   double cosine, vec1[3], vec2[3],  d1i, d2i, dist2;
00208   int j;
00209 
00210   cosine=0.0;
00211   /* vector from p_mid to p_left */
00212   get_mi_vector(vec1, p_mid->r.p, p_left->r.p);
00213   dist2 = sqrlen(vec1);
00214   d1i = 1.0 / sqrt(dist2);
00215   for(j=0;j<3;j++) vec1[j] *= d1i;
00216   /* vector from p_right to p_mid */
00217   get_mi_vector(vec2, p_right->r.p, p_mid->r.p);
00218   dist2 = sqrlen(vec2);
00219   d2i = 1.0 / sqrt(dist2);
00220   for(j=0;j<3;j++) vec2[j] *= d2i;
00221   /* scalar produvt of vec1 and vec2 */
00222   cosine = scalar(vec1, vec2);
00223   if ( cosine >  TINY_COS_VALUE)  cosine = TINY_COS_VALUE;
00224   if ( cosine < -TINY_COS_VALUE)  cosine = -TINY_COS_VALUE;
00225   /* bond angle energy */
00226 #ifdef BOND_ANGLE_HARMONIC
00227   {
00228     double phi;
00229     phi =  acos(-cosine);
00230     *_energy = 0.5*iaparams->p.angle.bend*SQR(phi - iaparams->p.angle.phi0);
00231   }
00232 #endif
00233 #ifdef BOND_ANGLE_COSINE
00234   *_energy = iaparams->p.angle.bend*(cosine*iaparams->p.angle.cos_phi0 - sqrt(1-SQR(cosine))*iaparams->p.angle.sin_phi0+1);
00235 #endif
00236 #ifdef BOND_ANGLE_COSSQUARE
00237   *_energy = 0.5*iaparams->p.angle.bend*SQR(cosine + iaparams->p.angle.cos_phi0);
00238 #endif
00239   return 0;
00240 }
00241 
00242 #endif /* BOND_ANGLE_OLD */
00243 #endif /* ANGLE_H */