ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
endangledist.c
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 /** \file endangledist.c
00022  *
00023  *  Implementation of \ref endangledist.h
00024  */
00025 #include "utils.h"
00026 #include "interaction_data.h"
00027 #include "communication.h"
00028 #include "constraint.h"
00029 #include "grid.h"
00030 
00031 #ifdef BOND_ENDANGLEDIST
00032 
00033 int endangledist_set_params(int bond_type, double bend, double phi0 ,double distmin, double distmax)
00034 {
00035   if(bond_type < 0)
00036     return ES_ERROR;
00037 
00038   make_bond_type_exist(bond_type);
00039 
00040   bonded_ia_params[bond_type].p.endangledist.bend = bend;
00041   bonded_ia_params[bond_type].p.endangledist.phi0 = phi0;
00042   bonded_ia_params[bond_type].p.endangledist.distmin = distmin;
00043   bonded_ia_params[bond_type].p.endangledist.distmax = distmax;
00044 
00045   bonded_ia_params[bond_type].type = BONDED_IA_ENDANGLEDIST;
00046   /* Normally LENGTH=1 ANGLE=2 DIHEDRAL=3 
00047    * Here angle only requires one particle (other reference is wall constraint)
00048    */
00049   bonded_ia_params[bond_type].num  = 1;
00050 
00051   /* broadcast interaction parameters */
00052   mpi_bcast_ia_params(bond_type, -1); 
00053 
00054   return ES_OK;
00055 }
00056 
00057 #ifdef CONSTRAINTS
00058 /// Calculates the minimum distance between a particle to any wall constraint
00059 static double calc_pwdist(Particle *p1, Bonded_ia_parameters *iaparams, int *clconstr)
00060 {
00061   int j,k,img[3];
00062   double distwallmin=0.0, normal=0.0;
00063   double folded_pos_p1[3];
00064   double pwdist[n_constraints];
00065   Constraint_wall wall;
00066 
00067   /*fprintf(stdout,"  Entering calc_pwdist:\n");*/
00068 
00069   /* folds coordinates of p_left into original box */
00070   memcpy(folded_pos_p1, p1->r.p, 3*sizeof(double));
00071   memcpy(img, p1->l.i, 3*sizeof(int));
00072   fold_position(folded_pos_p1, img);
00073   /*fprintf(stdout,"        p1= %9.6f %9.6f %9.6f\n",p1->r.p[0],p1->r.p[1],p1->r.p[2]);*/
00074 
00075   /* Gets and tests wall data */
00076   for(k=0;k<n_constraints;k++) {
00077     switch(constraints[k].type) {
00078       case CONSTRAINT_WAL: 
00079       wall=constraints[k].c.wal;
00080       /* check that constraint wall normal is normalised */
00081       for(j=0;j<3;j++) normal += wall.n[j] * wall.n[j];
00082       if (sqrt(normal) != 1.0) {
00083         for(j=0;j<3;j++) wall.n[j]=wall.n[j]/normal;
00084       }
00085       break;
00086     }
00087   }
00088 
00089   /* Calculate distance of end particle from closest wall */
00090   for(k=0;k<n_constraints;k++) {
00091     switch(constraints[k].type) {
00092       case CONSTRAINT_WAL:
00093       wall=constraints[k].c.wal;
00094       /* distwallmin is distance of closest wall from p1 */
00095       pwdist[k]=-1.0 * wall.d;
00096       for(j=0;j<3;j++) {
00097         pwdist[k] += folded_pos_p1[j] * wall.n[j];
00098       }
00099       if (k==0) {
00100         distwallmin=pwdist[k];
00101       } else {
00102         if (pwdist[k] < distwallmin) {
00103           distwallmin = pwdist[k];
00104           *clconstr =  k;
00105         }
00106       }
00107       /*fprintf(stdout,"  k=%d  clconstr=%d\n",k,*clconstr);*/
00108       break;
00109     }
00110   }
00111   /*
00112     if (distwallmin <= iaparams->p.endangledist.distmax) {
00113     fprintf(stdout,"  clconstr=%d  distwallmin=%f  distmx=%f\n",*clconstr,distwallmin,distmx);
00114   }
00115   */
00116   return distwallmin;
00117 }
00118 
00119 /// Calculate angle that p1--p2 makes with wall constraint
00120 static double calc_pwangle(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, int *constr)
00121 {
00122   int j;
00123   double dist,di,cosine,phi;
00124   double vec[3];
00125 
00126   /* vector from p1 to p2 */
00127   get_mi_vector(vec, p2->r.p, p1->r.p);
00128   dist = sqrlen(vec);
00129   di = 1.0/sqrt(dist);
00130   for(j=0;j<3;j++) vec[j] *= di;
00131   /*
00132   fprintf(stdout,"Normalised: p1= %9.6f %9.6f %9.6f   p1= %9.6f %9.6f %9.6f   vec= %9.6f %9.6f %9.6f\n",p1->r.p[0],p1->r.p[1],p1->r.p[2],p2->r.p[0],p2->r.p[1],p2->r.p[2],vec[0],vec[1],vec[2]);
00133   */
00134   /* vectors are normalised so cosine is just cos(angle_between_vec1_and_vec2)
00135    * Wall is closest wall to particle
00136    */
00137 
00138   cosine = scalar(vec, constraints[*constr].c.wal.n);
00139   if ( cosine >  TINY_COS_VALUE)  cosine =  TINY_COS_VALUE;
00140   if ( cosine < -TINY_COS_VALUE)  cosine = -TINY_COS_VALUE;
00141   phi=acos(cosine);
00142 
00143   /*
00144   fprintf(stdout,"Angle with wall 0=%f  ",(acos(scalar(vec, constraints[0].c.wal.n)))*180.0/PI);
00145   fprintf(stdout,"Angle with wall 1=%f  ",(acos(scalar(vec, constraints[1].c.wal.n)))*180.0/PI);
00146   fprintf(stdout,"dxy=%f  dz=%f  angle=%f\n",sqrt(vec[0]*vec[0]+vec[1]*vec[1]),vec[2],atan(sqrt(vec[0]*vec[0]+vec[1]*vec[1])/vec[2])*180.0/PI);
00147   fprintf(stdout,"Angle with closest wall %d=%f  ",*constr,(acos(scalar(vec, constraints[*constr].c.wal.n)))*180.0/PI);
00148   */
00149   return phi;
00150 }
00151 #endif
00152 
00153 ///
00154 int calc_endangledist_pair_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double force1[3], double force2[3])
00155 {
00156 
00157   int i=0;
00158   int clconstr=0;
00159   //  double distwallmin=0.0, distmx, distmn;
00160   double bend=0.0,phieq=0.0,phi=0.0,distwallmin=0.0, distmx, distmn, dist, di;
00161   double smooth, sinphi, cosphi, fac_a, fac_b, gradharm1, gradharm2;
00162   double vec[3],dsmooth[3],f1a[3],f1b[3],f2a[3];
00163 
00164   /*fprintf(stdout,"\nEntering calc_endangledist_pair_force:\n");*/
00165 
00166   distwallmin = calc_pwdist(p1, iaparams, &clconstr);
00167   distmx = iaparams->p.endangledist.distmax;
00168   distmn = iaparams->p.endangledist.distmin;
00169 
00170   if (distwallmin < distmx) {
00171     /* function which goes smoothly from 0 to 1 as z goes from distmax to distmin */
00172     if (distwallmin < distmn) {
00173       smooth = 1.0;
00174       for(i=0;i<3;i++) {
00175         dsmooth[i] = 0.0;
00176       }
00177     } else {
00178       smooth = 0.5*(cos((distwallmin-distmn)/(distmx-distmn)*PI)+1.0);
00179       for(i=0;i<3;i++) {
00180         dsmooth[i] = -0.5*PI/(distmx-distmn)*sin((distwallmin-distmn)/(distmx-distmn)*PI)*constraints[clconstr].c.wal.n[i];
00181       }
00182     }
00183     /* Get vector from particle 1 to particle 2 */
00184     get_mi_vector(vec, p2->r.p, p1->r.p);
00185     dist = sqrlen(vec);
00186     di = 1.0/sqrt(dist);
00187     /*
00188     for(j=0;j<3;j++) vec[j] *= di;
00189     */
00190     /* Calculate angle that p1-p2 makes with wall */
00191     phi = calc_pwangle(p1, p2, iaparams, &clconstr);
00192 
00193     sinphi = sin(phi);
00194     cosphi = cos(phi);
00195     bend   = iaparams->p.endangledist.bend;
00196     phieq  = iaparams->p.endangledist.phi0;
00197 
00198     /*
00199     fprintf(stdout,"  Bead %4d: Cl.wall=%2d  distwallmin=%9.6f  \n",p1->p.identity,clconstr,distwallmin);
00200     fprintf(stdout,"    vector=(%f %f %f)\n",vec[0],vec[1],vec[2]);
00201     fprintf(stdout,"pos1=(%f %f %f)  pos2=(%f %f %f)  distwallmin=%9.6f  angle=%9.6f\n",p1->r.p[0],p1->r.p[1],p1->r.p[2],p2->r.p[0],p2->r.p[1],p2->r.p[2],distwallmin,phi*180.0/PI);
00202     */
00203 
00204 #ifdef BOND_ENDANGLEDIST_HARMONIC
00205     /* Force = -dU/dr_i= k*smooth*(phi-phi0)/sin(phi)(cosphi*vec + n)/|vec| */
00206     fac_a = bend*(phi-phieq)/sinphi;
00207     fac_b = 0.5*bend*SQR(phi-phieq);
00208     for(i=0;i<3;i++) {
00209       gradharm1 = -1.0*fac_a*(cosphi*vec[i]-constraints[clconstr].c.wal.n[i])*di;
00210       gradharm2 = -1.0*gradharm1;
00211       f1a[i] = smooth*gradharm1;
00212       f1b[i] = dsmooth[i]*fac_b;
00213       f2a[i] = smooth*gradharm2;
00214       force1[i] = -1.0*(f1a[i]+f1b[i]);
00215       force2[i] = -1.0*f2a[i];
00216     }
00217     /*
00218     fprintf(stdout,"    f1=(% 9.6f % 9.6f % 9.6f)  ",f1[0],f1[1],f1[2]);
00219     fprintf(stdout,"    f2=(% 9.6f % 9.6f % 9.6f)\n",f2[0],f2[1],f2[2]);
00220     fprintf(stdout," force=(% 9.6f % 9.6f % 9.6f)  ",force1[0],force1[1],force1[2]);
00221     fprintf(stdout," force2=(% 9.6f % 9.6f % 9.6f)\n",force2[0],force2[1],force2[2]);
00222     */
00223   } else if (distwallmin >= distmx) {
00224     for(i=0;i<3;i++) {
00225       force1[i] = 0.0;
00226       force2[i] = 0.0;
00227     }
00228   }
00229 #endif
00230 
00231   ONEPART_TRACE(if(p1->p.identity==check_id) fprintf(stderr,"%d: OPT: ENDANGLEDIST f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p1->f.f[0],p1->f.f[1],p1->f.f[2],p2->p.identity,dist2,fac));
00232   ONEPART_TRACE(if(p2->p.identity==check_id) fprintf(stderr,"%d: OPT: ENDANGLEDIST f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p2->f.f[0],p2->f.f[1],p2->f.f[2],p1->p.identity,dist2,fac));
00233 
00234   return 0;
00235 }
00236 
00237 int endangledist_pair_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double *_energy)
00238 {
00239   int clconstr=0;
00240   double bend=0.0,phieq=0.0,phi=0.0;
00241   double distwallmin=0.0, distmx, distmn, smooth;
00242 
00243   /*fprintf(stdout,"Entering endangledist_pair_energy\n");*/
00244 
00245   distwallmin = calc_pwdist(p1, iaparams, &clconstr);
00246   /* fprintf(stdout,"clconstr=%d\n",clconstr);*/
00247   /* fprintf(stdout,"Minimum particle-wall distance=%f\n",distwallmin);*/
00248   distmx = iaparams->p.endangledist.distmax;
00249   distmn = iaparams->p.endangledist.distmin;
00250 
00251 #ifdef BOND_ENDANGLEDIST_HARMONIC
00252   if (distwallmin < distmx) {
00253     /* function which goes smoothly from 0 to 1 as z goes from distmax to distmin */
00254     if (distwallmin < distmn) {
00255       smooth = 1.0;
00256     } else {
00257       smooth = 0.5*(cos((distwallmin-distmn)/(distmx-distmn)*PI)+1);
00258     }
00259     /* Calculate angle that p1-p2 makes with wall */
00260     phi = calc_pwangle(p1, p2, iaparams, &clconstr);
00261     /*fprintf(stdout,"clconstr=%d smooth=%f\n",clconstr,smooth);*/
00262     bend   = iaparams->p.endangledist.bend;
00263     phieq  = iaparams->p.endangledist.phi0;
00264     *_energy = 0.5*bend*smooth*SQR(phi - phieq);
00265   } else if (distwallmin >= distmx) {
00266     *_energy = 0.0;
00267   }
00268 #endif
00269 
00270   return 0;
00271 }
00272 
00273 #endif
00274