ESPResSo 3.2.0-167-g2c9ead1-git
Extensible Simulation Package for Soft Matter Research
constraint.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 constraint.c
00022     Implementation of \ref constraint.h "constraint.h", here it's just the parsing stuff.
00023 */
00024 
00025 #include "constraint.h"
00026 #include "energy.h"
00027 #include "forces.h"
00028 #include "tunable_slip.h"
00029 
00030 // for the charged rod "constraint"
00031 #define C_GAMMA   0.57721566490153286060651209008
00032 
00033 int reflection_happened;
00034 
00035 #ifdef CONSTRAINTS
00036 
00037 int n_constraints       = 0;
00038 Constraint *constraints = NULL;
00039 
00040 Constraint *generate_constraint()
00041 {
00042   n_constraints++;
00043   constraints = realloc(constraints,n_constraints*sizeof(Constraint));
00044   constraints[n_constraints-1].type = CONSTRAINT_NONE;
00045   constraints[n_constraints-1].part_rep.p.identity = -n_constraints;
00046   
00047   return &constraints[n_constraints-1];
00048 }
00049 
00050 void init_constraint_forces()
00051 {
00052   int n, i;
00053   
00054   for (n = 0; n < n_constraints; n++)
00055     for (i = 0; i < 3; i++)
00056       constraints[n].part_rep.f.f[i] = 0;
00057 }
00058 
00059 
00060 static double sign(double x) {
00061   if (x > 0)
00062     return 1.;
00063   else
00064     return -1;
00065 }
00066 
00067 static double max(double x1, double x2) {
00068   return x1>x2?x1:x2;
00069 }
00070 
00071 void calculate_wall_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_wall *c, double *dist, double *vec)
00072 {
00073   int i;
00074 
00075   *dist = -c->d;
00076   for(i=0;i<3;i++) *dist += ppos[i]*c->n[i];
00077   
00078   for(i=0;i<3;i++) vec[i] = c->n[i] * *dist;
00079   
00080 }
00081 
00082 
00083 void calculate_sphere_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_sphere *c, double *dist, double *vec)
00084 {
00085   int i;
00086   double fac,  c_dist;
00087 
00088   c_dist=0.0;
00089   for(i=0;i<3;i++) {
00090     vec[i] = c->pos[i] - ppos[i];
00091     c_dist += SQR(vec[i]);
00092   }
00093   c_dist = sqrt(c_dist);
00094   
00095   if ( c->direction == -1 ) {
00096   /* apply force towards inside the sphere */
00097     *dist = c->rad - c_dist;
00098     fac = *dist / c_dist;
00099     for(i=0;i<3;i++) vec[i] *= fac;
00100   } else {
00101    /* apply force towards outside the sphere */
00102     *dist = c_dist - c->rad;
00103     fac = *dist / c_dist;
00104     for(i=0;i<3;i++) vec[i] *= -fac;
00105   }
00106 }
00107 
00108 
00109 void calculate_maze_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_maze *c, double *dist, double *vec)
00110 {
00111   int i,min_axis,cursph[3],dim;
00112   double diasph,fac,c_dist,sph_dist,cyl_dist,temp_dis;
00113   double sph_vec[3],cyl_vec[3];
00114 
00115   dim=(int) c->dim;
00116   diasph = box_l[0]/c->nsphere;
00117 
00118   /* First determine the distance to the sphere */
00119   c_dist=0.0;
00120   for(i=0;i<3;i++) {
00121     cursph[i] = (int) (ppos[i]/diasph);
00122     sph_vec[i] = (cursph[i]+0.5) * diasph  - (ppos[i]);
00123     c_dist += SQR(sph_vec[i]);
00124   }
00125   c_dist = sqrt(c_dist);
00126   sph_dist = c->sphrad - c_dist;
00127   fac = sph_dist / c_dist;
00128   for(i=0;i<3;i++) cyl_vec[i] = sph_vec[i];
00129   for(i=0;i<3;i++) sph_vec[i] *= fac;
00130   
00131   /* Now calculate the cylinder stuff */
00132   /* have to check all 3 cylinders */
00133   min_axis=2;
00134   cyl_dist=sqrt(cyl_vec[0]*cyl_vec[0]+cyl_vec[1]*cyl_vec[1]);
00135   
00136   if(dim > 0 ){
00137     temp_dis=sqrt(cyl_vec[0]*cyl_vec[0]+cyl_vec[2]*cyl_vec[2]);
00138     if ( temp_dis < cyl_dist) {
00139         min_axis=1;
00140         cyl_dist=temp_dis;
00141     }
00142 
00143     if(dim > 1 ){
00144         temp_dis=sqrt(cyl_vec[1]*cyl_vec[1]+cyl_vec[2]*cyl_vec[2]);
00145         if ( temp_dis < cyl_dist) {
00146             min_axis=0;
00147             cyl_dist=temp_dis;
00148         }
00149     }
00150   }
00151   cyl_vec[min_axis]=0.;
00152   
00153   c_dist=cyl_dist;
00154   cyl_dist = c->cylrad - c_dist;
00155   fac = cyl_dist / c_dist;
00156   for(i=0;i<3;i++) cyl_vec[i] *= fac;
00157   
00158   /* Now decide between cylinder and sphere */
00159   if ( sph_dist > 0 ) {
00160     if ( sph_dist>cyl_dist ) {
00161         *dist = sph_dist;
00162         for(i=0;i<3;i++) vec[i] = sph_vec[i];
00163     } else {
00164         *dist = cyl_dist;
00165         for(i=0;i<3;i++) vec[i] = cyl_vec[i];  
00166     }
00167   } else {
00168     *dist = cyl_dist;
00169     for(i=0;i<3;i++) vec[i] = cyl_vec[i];  
00170   }
00171 }
00172 
00173 void calculate_cylinder_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_cylinder *c, double *dist, double *vec)
00174 {
00175   int i;
00176   double d_per,d_par,d_real,d_per_vec[3],d_par_vec[3],d_real_vec[3];
00177 
00178   d_real = 0.0;
00179   for(i=0;i<3;i++) {
00180     d_real_vec[i] = ppos[i] - c->pos[i];
00181     d_real += SQR(d_real_vec[i]);
00182   }
00183   d_real = sqrt(d_real);
00184     
00185   d_par=0.;
00186   for(i=0;i<3;i++) {
00187     d_par += (d_real_vec[i] * c->axis[i]);
00188   }
00189     
00190   for(i=0;i<3;i++) {
00191     d_par_vec[i] = d_par * c->axis[i] ;
00192     d_per_vec[i] = ppos[i] - (c->pos[i] + d_par_vec[i]) ;
00193   }
00194                 
00195   d_per=sqrt(SQR(d_real)-SQR(d_par));
00196   d_par = fabs(d_par) ;
00197 
00198   if ( c->direction == -1 ) {
00199     /*apply force towards inside cylinder */
00200     d_per = c->rad - d_per ;
00201     d_par = c->length - d_par;
00202     if (d_per < d_par )  {
00203       *dist = d_per ;   
00204       for (i=0; i<3;i++) {
00205         vec[i]= -d_per_vec[i] * d_per /  (c->rad - d_per) ;
00206       }
00207     } else {
00208       *dist = d_par ;
00209       for (i=0; i<3;i++) {
00210         vec[i]= -d_par_vec[i] * d_par /  (c->length - d_par) ;
00211       }
00212     }
00213   } else {
00214     /*apply force towards outside cylinder */
00215     d_per = d_per - c->rad ;
00216     d_par = d_par - c->length ;
00217     if (d_par < 0 )  {
00218       *dist = d_per ;   
00219       for (i=0; i<3;i++) {
00220         vec[i]= d_per_vec[i] * d_per /  (d_per + c->rad) ;
00221       }
00222     } else if ( d_per < 0) {
00223       *dist = d_par ;
00224       for (i=0; i<3;i++) {
00225         vec[i]= d_par_vec[i] * d_par /  (d_par + c->length) ;
00226       }
00227     } else {
00228       *dist = sqrt( SQR(d_par) + SQR(d_per)) ;
00229       for (i=0; i<3;i++) {
00230         vec[i]=
00231           d_per_vec[i] * d_per /  (d_per + c->rad) +
00232           d_par_vec[i] * d_par /  (d_par + c->length) ;
00233       } 
00234     }
00235   }
00236 }
00237 
00238 void calculate_rhomboid_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_rhomboid *c, double *dist, double *vec)
00239 {       
00240         double axb[3], bxc[3], axc[3];
00241         double A, B, C;
00242         double a_dot_bxc, b_dot_axc, c_dot_axb;
00243         double tmp;
00244         double d;
00245         
00246         //calculate a couple of vectors and scalars that are going to be used frequently
00247         
00248         axb[0] = c->a[1]*c->b[2] - c->a[2]*c->b[1];
00249         axb[1] = c->a[2]*c->b[0] - c->a[0]*c->b[2];
00250         axb[2] = c->a[0]*c->b[1] - c->a[1]*c->b[0];
00251         
00252         bxc[0] = c->b[1]*c->c[2] - c->b[2]*c->c[1];
00253         bxc[1] = c->b[2]*c->c[0] - c->b[0]*c->c[2];
00254         bxc[2] = c->b[0]*c->c[1] - c->b[1]*c->c[0];
00255         
00256         axc[0] = c->a[1]*c->c[2] - c->a[2]*c->c[1];
00257         axc[1] = c->a[2]*c->c[0] - c->a[0]*c->c[2];
00258         axc[2] = c->a[0]*c->c[1] - c->a[1]*c->c[0];
00259         
00260         a_dot_bxc = c->a[0]*bxc[0] + c->a[1]*bxc[1] + c->a[2]*bxc[2];
00261         b_dot_axc = c->b[0]*axc[0] + c->b[1]*axc[1] + c->b[2]*axc[2];
00262         c_dot_axb = c->c[0]*axb[0] + c->c[1]*axb[1] + c->c[2]*axb[2];
00263         
00264         //represent the distance from pos to ppos as a linear combination of the edge vectors.
00265         
00266         A = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2];
00267         A /= a_dot_bxc; 
00268         B = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2];
00269         B /= b_dot_axc; 
00270         C = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2];
00271         C /= c_dot_axb;
00272         
00273         //the coefficients tell whether ppos lies within the cone defined by pos and the adjacent edges
00274         
00275         if(A <= 0 && B <= 0 && C <= 0)
00276         {
00277                 vec[0] = ppos[0]-c->pos[0];
00278                 vec[1] = ppos[1]-c->pos[1];
00279                 vec[2] = ppos[2]-c->pos[2];
00280                 
00281                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00282                 
00283           return;
00284         }
00285         
00286         //check for cone at pos+a
00287 
00288         A = (ppos[0]-c->pos[0]-c->a[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2])*bxc[2];
00289         A /= a_dot_bxc; 
00290         B = (ppos[0]-c->pos[0]-c->a[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2])*axc[2];
00291         B /= b_dot_axc; 
00292         C = (ppos[0]-c->pos[0]-c->a[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2])*axb[2];
00293         C /= c_dot_axb;
00294 
00295         if(A >= 0 && B <= 0 && C <= 0)
00296         {
00297                 vec[0] = ppos[0]-c->pos[0]-c->a[0];
00298                 vec[1] = ppos[1]-c->pos[1]-c->a[1];
00299                 vec[2] = ppos[2]-c->pos[2]-c->a[2];
00300                 
00301                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00302                 
00303           return;
00304         }
00305         
00306         //check for cone at pos+b
00307 
00308         A = (ppos[0]-c->pos[0]-c->b[0])*bxc[0] + (ppos[1]-c->pos[1]-c->b[1])*bxc[1] + (ppos[2]-c->pos[2]-c->b[2])*bxc[2];
00309         A /= a_dot_bxc; 
00310         B = (ppos[0]-c->pos[0]-c->b[0])*axc[0] + (ppos[1]-c->pos[1]-c->b[1])*axc[1] + (ppos[2]-c->pos[2]-c->b[2])*axc[2];
00311         B /= b_dot_axc; 
00312         C = (ppos[0]-c->pos[0]-c->b[0])*axb[0] + (ppos[1]-c->pos[1]-c->b[1])*axb[1] + (ppos[2]-c->pos[2]-c->b[2])*axb[2];
00313         C /= c_dot_axb;
00314 
00315         if(A <= 0 && B >= 0 && C <= 0)
00316         {
00317                 vec[0] = ppos[0]-c->pos[0]-c->b[0];
00318                 vec[1] = ppos[1]-c->pos[1]-c->b[1];
00319                 vec[2] = ppos[2]-c->pos[2]-c->b[2];
00320                 
00321                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00322                 
00323                 return;
00324         }
00325         
00326         //check for cone at pos+c
00327 
00328         A = (ppos[0]-c->pos[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->c[2])*bxc[2];
00329         A /= a_dot_bxc; 
00330         B = (ppos[0]-c->pos[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->c[2])*axc[2];
00331         B /= b_dot_axc; 
00332         C = (ppos[0]-c->pos[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->c[2])*axb[2];
00333         C /= c_dot_axb;
00334 
00335         if(A <= 0 && B <= 0 && C >= 0)
00336         {
00337                 vec[0] = ppos[0]-c->pos[0]-c->c[0];
00338                 vec[1] = ppos[1]-c->pos[1]-c->c[1];
00339                 vec[2] = ppos[2]-c->pos[2]-c->c[2];
00340                 
00341                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00342         
00343           return;
00344         }
00345         
00346         //check for cone at pos+a+b
00347 
00348         A = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*bxc[2];
00349         A /= a_dot_bxc; 
00350         B = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*axc[2];
00351         B /= b_dot_axc; 
00352         C = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*axb[2];
00353         C /= c_dot_axb;
00354 
00355         if(A >= 0 && B >= 0 && C <= 0)
00356         {
00357                 vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0];
00358                 vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1];
00359                 vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2];
00360                 
00361                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00362 
00363     return;
00364         }
00365         
00366         //check for cone at pos+a+c
00367 
00368         A = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*bxc[2];
00369         A /= a_dot_bxc; 
00370         B = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*axc[2];
00371         B /= b_dot_axc; 
00372         C = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*axb[2];
00373         C /= c_dot_axb;
00374 
00375         if(A >= 0 && B <= 0 && C >= 0)
00376         {
00377                 vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->c[0];
00378                 vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->c[1];
00379                 vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->c[2];
00380                 
00381                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00382 
00383     return;
00384         }
00385         
00386         //check for cone at pos+a+c
00387 
00388         A = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*bxc[2];
00389         A /= a_dot_bxc; 
00390         B = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*axc[2];
00391         B /= b_dot_axc; 
00392         C = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*axb[2];
00393         C /= c_dot_axb;
00394 
00395         if(A <= 0 && B >= 0 && C >= 0)
00396         {
00397                 vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0];
00398                 vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1];
00399                 vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2];
00400                 
00401                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00402 
00403     return;
00404         }
00405         
00406         //check for cone at pos+a+b+c
00407 
00408         A = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*bxc[2];
00409         A /= a_dot_bxc; 
00410         B = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*axc[2];
00411         B /= b_dot_axc; 
00412         C = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*axb[2];
00413         C /= c_dot_axb;
00414 
00415         if(A >= 0 && B >= 0 && C >= 0)
00416         {
00417                 vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0];
00418                 vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1];
00419                 vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2];
00420                 
00421                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00422 
00423     return;
00424         }
00425         
00426         //check for prism at edge pos, a
00427         
00428         B = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2];
00429         B /= b_dot_axc;
00430         C = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2];
00431         C /= c_dot_axb;
00432         
00433         if(B <= 0 && C <= 0)
00434         {
00435                 tmp = (ppos[0]-c->pos[0])*c->a[0] + (ppos[1]-c->pos[1])*c->a[1] + (ppos[2]-c->pos[2])*c->a[2];
00436                 tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2];
00437                 
00438                 vec[0] = ppos[0]-c->pos[0] - c->a[0]*tmp;
00439                 vec[1] = ppos[1]-c->pos[1] - c->a[1]*tmp;
00440                 vec[2] = ppos[2]-c->pos[2] - c->a[2]*tmp;
00441                 
00442                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00443                 
00444     return;
00445         }
00446         
00447         //check for prism at edge pos, b
00448 
00449         A = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2];
00450         A /= a_dot_bxc;
00451         C = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2];
00452         C /= c_dot_axb;
00453 
00454         if(A <= 0 && C <= 0)
00455         {
00456                 tmp = (ppos[0]-c->pos[0])*c->b[0] + (ppos[1]-c->pos[1])*c->b[1] + (ppos[2]-c->pos[2])*c->b[2];
00457                 tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2];
00458         
00459                 vec[0] = ppos[0]-c->pos[0] - c->b[0]*tmp;
00460                 vec[1] = ppos[1]-c->pos[1] - c->b[1]*tmp;
00461                 vec[2] = ppos[2]-c->pos[2] - c->b[2]*tmp;
00462         
00463                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00464         
00465     return;
00466         }
00467         
00468         //check for prism at edge pos, c
00469 
00470         A = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2];
00471         A /= a_dot_bxc;
00472         B = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2];
00473         B /= b_dot_axc;
00474 
00475         if(A <= 0 && B <= 0)
00476         {
00477                 tmp = (ppos[0]-c->pos[0])*c->c[0] + (ppos[1]-c->pos[1])*c->c[1] + (ppos[2]-c->pos[2])*c->c[2];
00478                 tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2];
00479 
00480                 vec[0] = ppos[0]-c->pos[0] - c->c[0]*tmp;
00481                 vec[1] = ppos[1]-c->pos[1] - c->c[1]*tmp;
00482                 vec[2] = ppos[2]-c->pos[2] - c->c[2]*tmp;
00483 
00484                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00485 
00486     return;
00487         }
00488         
00489         //check for prism at edge pos+a, b
00490 
00491         A = (ppos[0]-c->pos[0]-c->a[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2])*bxc[2];
00492         A /= a_dot_bxc;
00493         C = (ppos[0]-c->pos[0]-c->a[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2])*axb[2];
00494         C /= c_dot_axb;
00495 
00496         if(A >= 0 && C <= 0)
00497         {
00498                 tmp = (ppos[0]-c->pos[0]-c->a[0])*c->b[0] + (ppos[1]-c->pos[1]-c->a[1])*c->b[1] + (ppos[2]-c->pos[2]-c->a[2])*c->b[2];
00499                 tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2];
00500 
00501                 vec[0] = ppos[0]-c->pos[0]-c->a[0] - c->b[0]*tmp;
00502                 vec[1] = ppos[1]-c->pos[1]-c->a[1] - c->b[1]*tmp;
00503                 vec[2] = ppos[2]-c->pos[2]-c->a[2] - c->b[2]*tmp;
00504 
00505                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00506 
00507     return;
00508         }
00509         
00510         //check for prism at edge pos+a, c
00511 
00512         A = (ppos[0]-c->pos[0]-c->a[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2])*bxc[2];
00513         A /= a_dot_bxc;
00514         B = (ppos[0]-c->pos[0]-c->a[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2])*axc[2];
00515         B /= b_dot_axc;
00516 
00517         if(A >= 0 && B <= 0)
00518         {
00519                 tmp = (ppos[0]-c->pos[0]-c->a[0])*c->c[0] + (ppos[1]-c->pos[1]-c->a[1])*c->c[1] + (ppos[2]-c->pos[2]-c->a[2])*c->c[2];
00520                 tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2];
00521 
00522                 vec[0] = ppos[0]-c->pos[0]-c->a[0] - c->c[0]*tmp;
00523                 vec[1] = ppos[1]-c->pos[1]-c->a[1] - c->c[1]*tmp;
00524                 vec[2] = ppos[2]-c->pos[2]-c->a[2] - c->c[2]*tmp;
00525 
00526                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00527 
00528     return;
00529         }
00530         
00531         //check for prism at edge pos+b+c, c
00532 
00533         A = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*bxc[2];
00534         A /= a_dot_bxc;
00535         B = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*axc[2];
00536         B /= b_dot_axc;
00537 
00538         if(A <= 0 && B >= 0)
00539         {
00540                 tmp = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*c->c[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*c->c[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*c->c[2];
00541                 tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2];
00542 
00543                 vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0] - c->c[0]*tmp;
00544                 vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1] - c->c[1]*tmp;
00545                 vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2] - c->c[2]*tmp;
00546 
00547                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00548 
00549     return;
00550         }
00551         
00552         //check for prism at edge pos+b+c, b
00553 
00554         A = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*bxc[2];
00555         A /= a_dot_bxc;
00556         C = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*axb[2];
00557         C /= c_dot_axb;
00558 
00559         if(A <= 0 && C >= 0)
00560         {
00561                 tmp = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*c->b[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*c->b[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*c->b[2];
00562                 tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2];
00563 
00564                 vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0] - c->b[0]*tmp;
00565                 vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1] - c->b[1]*tmp;
00566                 vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2] - c->b[2]*tmp;
00567 
00568                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00569 
00570     return;
00571         }
00572         
00573         //check for prism at edge pos+b+c, a
00574 
00575         B = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*axc[2];
00576         B /= b_dot_axc;
00577         C = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*axb[2];
00578         C /= c_dot_axb;
00579                                                                                                                                 
00580         if(B >= 0 && C >= 0)
00581         {
00582                 tmp = (ppos[0]-c->pos[0]-c->b[0]-c->c[0])*c->a[0] + (ppos[1]-c->pos[1]-c->b[1]-c->c[1])*c->a[1] + (ppos[2]-c->pos[2]-c->b[2]-c->c[2])*c->a[2];
00583                 tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2];
00584 
00585                 vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0] - c->a[0]*tmp;
00586                 vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1] - c->a[1]*tmp;
00587                 vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2] - c->a[2]*tmp;
00588 
00589                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00590 
00591     return;
00592         }
00593         
00594         //check for prism at edge pos+a+b, a
00595 
00596         B = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*axc[2];
00597         B /= b_dot_axc;
00598         C = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*axb[2];
00599         C /= c_dot_axb;
00600 
00601         if(B >= 0 && C <= 0)
00602         {
00603                 tmp = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*c->a[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*c->a[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*c->a[2];
00604                 tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2];
00605 
00606                 vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0] - c->a[0]*tmp;
00607                 vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1] - c->a[1]*tmp;
00608                 vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2] - c->a[2]*tmp;
00609 
00610                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00611 
00612     return;
00613         }
00614         
00615         //check for prism at edge pos+a+b, c
00616 
00617         A = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*bxc[2];
00618         A /= a_dot_bxc;
00619         B = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*axc[2];
00620         B /= b_dot_axc;
00621 
00622         if(A >= 0 && B >= 0)
00623         {
00624                 tmp = (ppos[0]-c->pos[0]-c->a[0]-c->b[0])*c->c[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1])*c->c[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2])*c->c[2];
00625                 tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2];
00626 
00627                 vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0] - c->c[0]*tmp;
00628                 vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1] - c->c[1]*tmp;
00629                 vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2] - c->c[2]*tmp;
00630 
00631                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00632 
00633     return;
00634         }
00635         
00636         //check for prism at edge pos+a+c, a
00637 
00638         B = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*axc[2];
00639         B /= b_dot_axc;
00640         C = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*axb[2];
00641         C /= c_dot_axb;
00642 
00643         if(B <= 0 && C >= 0)
00644         {
00645                 tmp = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*c->a[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*c->a[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*c->a[2];
00646                 tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2];
00647 
00648                 vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->c[0] - c->a[0]*tmp;
00649                 vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->c[1] - c->a[1]*tmp;
00650                 vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->c[2] - c->a[2]*tmp;
00651 
00652                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00653 
00654     return;
00655         }
00656         
00657         //check for prism at edge pos+a+c, b
00658 
00659         A = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*bxc[2];
00660         A /= a_dot_bxc;
00661         C = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*axb[2];
00662         C /= c_dot_axb;
00663 
00664         if(A >= 0 && C >= 0)
00665         {
00666                 tmp = (ppos[0]-c->pos[0]-c->a[0]-c->c[0])*c->b[0] + (ppos[1]-c->pos[1]-c->a[1]-c->c[1])*c->b[1] + (ppos[2]-c->pos[2]-c->a[2]-c->c[2])*c->b[2];
00667                 tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2];
00668 
00669                 vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->c[0] - c->b[0]*tmp;
00670                 vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->c[1] - c->b[1]*tmp;
00671                 vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->c[2] - c->b[2]*tmp;
00672 
00673                 *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
00674 
00675     return;
00676         }
00677         
00678         //check for face with normal -axb
00679         
00680         *dist = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2];
00681         *dist *= -1.;
00682         
00683         if(*dist >= 0)
00684         {
00685                 tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] );
00686                 *dist /= tmp;
00687         
00688                 vec[0] = -*dist * axb[0]/tmp;
00689                 vec[1] = -*dist * axb[1]/tmp;
00690                 vec[2] = -*dist * axb[2]/tmp;
00691         
00692                 *dist *= c->direction;
00693 
00694     return;
00695         }
00696         
00697         //calculate distance to face with normal axc
00698 
00699         *dist = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2];
00700         
00701         if(*dist >= 0)
00702         {
00703                 tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] );
00704                 *dist /= tmp;
00705         
00706                 vec[0] = *dist * axc[0]/tmp;
00707                 vec[1] = *dist * axc[1]/tmp;
00708                 vec[2] = *dist * axc[2]/tmp;
00709 
00710                 *dist *= c->direction;
00711 
00712     return;
00713         }
00714         
00715         //calculate distance to face with normal -bxc
00716 
00717         *dist = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2];
00718         *dist *= -1.;
00719         
00720         if(*dist >= 0)
00721         {
00722                 tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] );
00723                 *dist /= tmp;
00724                 
00725                 vec[0] = -*dist * bxc[0]/tmp;
00726                 vec[1] = -*dist * bxc[1]/tmp;
00727                 vec[2] = -*dist * bxc[2]/tmp;
00728                 
00729                 *dist *= c->direction;
00730 
00731     return;
00732         }
00733         
00734         //calculate distance to face with normal axb
00735         
00736         *dist = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*axb[2];
00737         
00738         if(*dist >= 0)
00739         {
00740                 tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] );
00741                 *dist /= tmp;
00742 
00743                 vec[0] = *dist * axb[0]/tmp;
00744                 vec[1] = *dist * axb[1]/tmp;
00745                 vec[2] = *dist * axb[2]/tmp;
00746         
00747                 *dist *= c->direction;
00748 
00749     return;
00750         }
00751                                                                                                                                                                         
00752         //calculate distance to face with normal -axc
00753 
00754         *dist = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*axc[2];
00755         *dist *= -1.;
00756         
00757         if(*dist >= 0)
00758         {
00759                 tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] );
00760                 *dist /= tmp;
00761 
00762                 vec[0] = -*dist * axc[0]/tmp;
00763                 vec[1] = -*dist * axc[1]/tmp;
00764                 vec[2] = -*dist * axc[2]/tmp;
00765                 
00766                 *dist *= c->direction;
00767 
00768     return;
00769         }
00770                                                                                                                                                 
00771         //calculate distance to face with normal bxc
00772 
00773         *dist = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*bxc[2];
00774         
00775         if(*dist >= 0)
00776         {
00777                 tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] );
00778                 *dist /= tmp;
00779 
00780                 vec[0] = *dist * bxc[0]/tmp;
00781                 vec[1] = *dist * bxc[1]/tmp;
00782                 vec[2] = *dist * bxc[2]/tmp;
00783                 
00784                 *dist *= c->direction;
00785 
00786     return;
00787         }
00788         
00789         //ppos lies within rhomboid. Find nearest wall for interaction.
00790          
00791         //check for face with normal -axb
00792         
00793         *dist = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2];
00794         *dist *= -1.;
00795         tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] );
00796         *dist /= tmp;
00797         
00798         vec[0] = -*dist * axb[0]/tmp;
00799         vec[1] = -*dist * axb[1]/tmp;
00800         vec[2] = -*dist * axb[2]/tmp;
00801         
00802         *dist *= c->direction;
00803 
00804         //calculate distance to face with normal axc
00805 
00806         d = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2];
00807         tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] );
00808         d /= tmp;
00809         
00810         if(abs(d) < abs(*dist))
00811         {
00812                 vec[0] = d * axc[0]/tmp;
00813                 vec[1] = d * axc[1]/tmp;
00814                 vec[2] = d * axc[2]/tmp;
00815         
00816                 *dist = c->direction * d;
00817         }
00818 
00819         //calculate distance to face with normal -bxc
00820 
00821         d = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2];
00822         d *= -1.;
00823         tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] );
00824         d /= tmp;
00825 
00826         if(abs(d) < abs(*dist))
00827         {                                                       
00828                 vec[0] = -d * bxc[0]/tmp;
00829                 vec[1] = -d * bxc[1]/tmp;
00830                 vec[2] = -d * bxc[2]/tmp;
00831 
00832                 *dist = c->direction * d;
00833         }
00834         
00835         //calculate distance to face with normal axb
00836 
00837         d = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*axb[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*axb[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*axb[2];
00838         tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] );
00839         d /= tmp;
00840         
00841         if(abs(d) < abs(*dist))
00842         {                                                                                                                                                                       
00843                 vec[0] = d * axb[0]/tmp;
00844                 vec[1] = d * axb[1]/tmp;
00845                 vec[2] = d * axb[2]/tmp;
00846 
00847                 *dist = c->direction * d;
00848         }
00849         
00850         //calculate distance to face with normal -axc
00851 
00852         d = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*axc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*axc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*axc[2];
00853         d *= -1.;
00854         tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] );
00855         d /= tmp;
00856 
00857         if(abs(d) < abs(*dist))
00858         {                                                                                                                                                                               
00859                 vec[0] = -d * axc[0]/tmp;
00860                 vec[1] = -d * axc[1]/tmp;
00861                 vec[2] = -d * axc[2]/tmp;
00862 
00863                 *dist = c->direction * d;
00864         }
00865                                                                                                                                                 
00866         //calculate distance to face with normal bxc
00867 
00868         d = (ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0])*bxc[0] + (ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1])*bxc[1] + (ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2])*bxc[2];
00869         tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] );
00870         d /= tmp;
00871 
00872         if(abs(d) < abs(*dist))
00873         {                                                                                                                                                                               
00874                 vec[0] = d * bxc[0]/tmp;
00875                 vec[1] = d * bxc[1]/tmp;
00876                 vec[2] = d * bxc[2]/tmp;
00877         
00878                 *dist = c->direction * d;
00879         }
00880 }
00881 
00882 void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_pore *c, double *dist, double *vec)
00883 {
00884   int i;
00885   double c_dist[3];           /* cartesian distance from pore center */
00886   double z , r;             /* cylindrical coordinates, coordinate system parallel to
00887                                pore, origin at pore centera */
00888   double z_vec[3], r_vec[3]; /* cartesian vectors that correspond to these coordinates */
00889   double e_z[3], e_r[3];    /* unit vectors in the cylindrical coordinate system */
00890   /* helper variables, for performance reasons should the be move the the
00891    * constraint struct*/
00892      double slope, z_left, z_right;
00893   /* and another helper that is hopefully optmized out */
00894      double norm;
00895      double c1_r, c1_z, c2_r, c2_z;
00896      double cone_vector_r, cone_vector_z, p1_r, p1_z, dist_vector_z, dist_vector_r, temp;
00897 
00898      
00899      slope = (c->rad_right - c->rad_left)/2./(c->length-c->smoothing_radius);
00900 
00901   /* compute the position relative to the center of the pore */
00902   for(i=0;i<3;i++) {
00903     c_dist[i] = ppos[i] - c->pos[i]; 
00904   } 
00905   
00906   /* compute the component parallel to the pore axis */
00907   z =0.; 
00908   for(i=0;i<3;i++) {
00909     z += (c_dist[i] * c->axis[i]);
00910   }
00911   
00912   /* decompose the position into parallel and perpendicular to the axis */
00913   r = 0.;
00914   for(i=0;i<3;i++) {
00915     z_vec[i] = z * c->axis[i]; 
00916     r_vec[i] = c_dist[i] - z_vec[i];
00917     r += r_vec[i]*r_vec[i];
00918   }
00919   r = sqrt(r);
00920 
00921 
00922   /* calculate norm and unit vectors for both */
00923   norm = 0;
00924   for(i=0;i<3;i++) 
00925     norm += z_vec[i]*z_vec[i]; 
00926   norm = sqrt(norm);
00927   for(i=0;i<3;i++) 
00928     e_z[i] = c->axis[i];
00929   norm = 0;
00930   for(i=0;i<3;i++) 
00931     norm += r_vec[i]*r_vec[i]; 
00932   norm = sqrt(norm);
00933   for(i=0;i<3;i++) 
00934     e_r[i] = r_vec[i]/norm;
00935   
00936   /* c?_r/z and are the centers of the circles that are used to smooth 
00937    * the entrance of the pore in cylindrical coordinates*/
00938   c1_z = - (c->length - c->smoothing_radius);
00939   c2_z = + (c->length - c->smoothing_radius);
00940   z_left = c1_z - sign(slope) * sqrt(slope*slope/(1+slope*slope))*c->smoothing_radius;
00941   z_right = c2_z + sign(slope) * sqrt(slope*slope/(1+slope*slope))*c->smoothing_radius;
00942 
00943   c1_r = c->rad_left + slope * ( z_left + c->length ) +
00944       sqrt( c->smoothing_radius * c->smoothing_radius  - SQR( z_left - c1_z ) );
00945   c2_r = c->rad_left + slope * ( z_right + c->length ) +
00946       sqrt( c->smoothing_radius * c->smoothing_radius  - SQR( z_right - c2_z ) );
00947   c1_r = c->rad_left+c->smoothing_radius;
00948   c2_r = c->rad_right+c->smoothing_radius;
00949  
00950   /* Check if we are in the region of the left wall */
00951   if (( (r >= c1_r) && (z <= c1_z) ) || ( ( z <= 0 ) && (r>=max(c1_r, c2_r)))) {
00952     dist_vector_z=-z - c->length;
00953     dist_vector_r=0;
00954     *dist = -z - c->length;
00955     for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i];
00956     return;
00957   }
00958   /* Check if we are in the region of the right wall */
00959   if (( (r >= c2_r) && (z <= c2_z) ) || ( ( z >= 0 ) && (r>=max(c1_r, c2_r)))) {
00960     dist_vector_z=-z + c->length;
00961     dist_vector_r=0;
00962     *dist = +z - c->length;
00963     for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i];
00964     return;
00965   }
00966 
00967   /* check if the particle should feel the smoothed ends or the middle of the pore */
00968   /* calculate aufpunkt in z direction first.   */
00969 
00970   /* the distance of the particle from the pore cylinder/cone calculated by projection on the
00971    * cone normal. Should be > 0 if particle is inside the pore */
00972 
00973   cone_vector_z=1/sqrt(1+slope*slope);
00974   cone_vector_r=slope/sqrt(1+slope*slope);
00975 
00976   p1_r = c1_r+ ( (r-c1_r)*cone_vector_r + (z-c1_z)*cone_vector_z) * cone_vector_r;
00977   p1_z = c1_z+ ( (r-c1_r)*cone_vector_r + (z-c1_z)*cone_vector_z) * cone_vector_z;
00978 
00979   dist_vector_r = p1_r-r;
00980   dist_vector_z = p1_z-z;
00981 
00982   if ( p1_z>=c1_z && p1_z<=c2_z ) {
00983     if ( dist_vector_r <= 0  ) {
00984       if (z<0) {
00985         dist_vector_z=-z - c->length;
00986         dist_vector_r=0;
00987         *dist = -z - c->length;
00988         for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i];
00989         return;
00990       } else {
00991         dist_vector_z=-z + c->length;
00992         dist_vector_r=0;
00993         *dist = +z - c->length;
00994         for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i];
00995         return;
00996       }
00997     }
00998     temp=sqrt( dist_vector_r*dist_vector_r + dist_vector_z*dist_vector_z );
00999     *dist=temp-c->smoothing_radius;
01000     dist_vector_r-=dist_vector_r/temp*c->smoothing_radius;
01001     dist_vector_z-=dist_vector_z/temp*c->smoothing_radius;
01002     for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i];
01003     return;
01004   }
01005 
01006 
01007   /* Check if we are in the range of the left smoothing circle */
01008   if (p1_z <= c1_z ) {
01009     /* distance from the smoothing center */
01010     norm = sqrt( (z - c1_z)*(z - c1_z) + (r - c1_r)*(r - c1_r) );
01011     *dist = norm - c->smoothing_radius;
01012     dist_vector_r=(c->smoothing_radius/norm -1)*(r - c1_r);
01013     dist_vector_z=(c->smoothing_radius/norm - 1)*(z - c1_z);
01014     for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i];
01015     return;
01016   }
01017   /* Check if we are in the range of the right smoothing circle */
01018   if (p1_z >= c2_z ) {
01019     norm = sqrt( (z - c2_z)*(z - c2_z) + (r - c2_r)*(r - c2_r) );
01020     *dist = norm - c->smoothing_radius;
01021     dist_vector_r=(c->smoothing_radius/norm -1)*(r - c2_r);
01022     dist_vector_z=(c->smoothing_radius/norm - 1)*(z - c2_z);
01023     for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i];
01024     return;
01025   }
01026   exit(printf("should never be reached, z %f, r%f\n",z, r));
01027 }
01028 
01029 void calculate_plane_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_plane *c, double *dist, double *vec)
01030 {
01031   int i;
01032   double c_dist_sqr,c_dist;
01033   
01034   c_dist_sqr=0.0;
01035   for(i=0;i<3;i++) {
01036     if(c->pos[i] >= 0) {
01037       vec[i] = c->pos[i] - ppos[i];
01038       c_dist_sqr += SQR(vec[i]);
01039     }else{
01040       vec[i] = 0.0;
01041       c_dist_sqr += SQR(vec[i]);
01042     }
01043   }
01044   c_dist = sqrt(c_dist_sqr);
01045   *dist = c_dist;
01046 
01047   
01048   for(i=0;i<3;i++) {
01049     vec[i] *= -1;
01050   }
01051 }
01052 
01053 void add_rod_force(Particle *p1, double ppos[3], Particle *c_p, Constraint_rod *c)
01054 {
01055 #ifdef ELECTROSTATICS
01056   int i;
01057   double fac, vec[2], c_dist_2;
01058 
01059   c_dist_2 = 0.0;
01060   for(i=0;i<2;i++) {
01061     vec[i] = ppos[i] - c->pos[i];
01062     c_dist_2 += SQR(vec[i]);
01063   }
01064 
01065   if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->lambda != 0.0) {
01066     fac = 2*coulomb.prefactor*c->lambda*p1->p.q/c_dist_2;
01067     p1->f.f[0]  += fac*vec[0];
01068     p1->f.f[1]  += fac*vec[1];
01069     c_p->f.f[0] -= fac*vec[0];
01070     c_p->f.f[1] -= fac*vec[1];
01071   }
01072 #endif
01073 }
01074 
01075 double rod_energy(Particle *p1, double ppos[3], Particle *c_p, Constraint_rod *c)
01076 {
01077 #ifdef ELECTROSTATICS
01078   int i;
01079   double vec[2], c_dist_2;
01080 
01081   c_dist_2 = 0.0;
01082   for(i=0;i<2;i++) {
01083     vec[i] = ppos[i] - c->pos[i];
01084     c_dist_2 += SQR(vec[i]);
01085   }
01086 
01087   if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->lambda != 0.0)
01088     return coulomb.prefactor*p1->p.q*c->lambda*(-log(c_dist_2*SQR(box_l_i[2])) + 2*(M_LN2 - C_GAMMA));
01089 #endif
01090   return 0;
01091 }
01092 
01093 void add_plate_force(Particle *p1, double ppos[3], Particle *c_p, Constraint_plate *c)
01094 {
01095 #ifdef ELECTROSTATICS
01096   double f;
01097 
01098   if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->sigma != 0.0) {
01099     f = 2*M_PI*coulomb.prefactor*c->sigma*p1->p.q;
01100     if (ppos[2] < c->pos)
01101       f = -f;
01102     p1->f.f[2]  += f;
01103     c_p->f.f[2] -= f;
01104   }
01105 #endif
01106 }
01107 
01108 double plate_energy(Particle *p1, double ppos[3], Particle *c_p, Constraint_plate *c)
01109 {
01110 #ifdef ELECTROSTATICS
01111   if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->sigma != 0.0)
01112     return -2*M_PI*coulomb.prefactor*c->sigma*p1->p.q*fabs(ppos[2] - c->pos);
01113 #endif
01114   return 0;
01115 }
01116 
01117 //ER
01118 void add_ext_magn_field_force(Particle *p1, Constraint_ext_magn_field *c)
01119 {
01120 #ifdef ROTATION
01121 #ifdef DIPOLES
01122   p1->f.torque[0] += p1->r.dip[1]*c->ext_magn_field[2]-p1->r.dip[2]*c->ext_magn_field[1];
01123   p1->f.torque[1] += p1->r.dip[2]*c->ext_magn_field[0]-p1->r.dip[0]*c->ext_magn_field[2];
01124   p1->f.torque[2] += p1->r.dip[0]*c->ext_magn_field[1]-p1->r.dip[1]*c->ext_magn_field[0];
01125 #endif
01126 #endif
01127 }
01128 
01129 double ext_magn_field_energy(Particle *p1, Constraint_ext_magn_field *c)
01130 {
01131 #ifdef DIPOLES
01132      return -1.0 * scalar(c->ext_magn_field,p1->r.dip);
01133 #endif
01134   return 0;
01135 }
01136 //end ER
01137 
01138 void reflect_particle(Particle *p1, double *distance_vec, int reflecting) {
01139   double vec[3];
01140   double norm; 
01141 
01142       double folded_pos[3];
01143       int img[3];
01144 
01145       memcpy(folded_pos, p1->r.p, 3*sizeof(double));
01146       memcpy(img, p1->l.i, 3*sizeof(int));
01147       fold_position(folded_pos, img);
01148 
01149       memcpy(vec, distance_vec, 3*sizeof(double));
01150 /* For Debugging your can show the folded coordinates of the particle before
01151  * and after the reflecting by uncommenting these lines  */
01152  //     printf("position before reflection %f %f %f\n",folded_pos[0], folded_pos[1], folded_pos[2]); 
01153 
01154 
01155        reflection_happened = 1;
01156        norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
01157        p1->r.p[0] = p1->r.p[0]-2*vec[0];
01158        p1->r.p[1] = p1->r.p[1]-2*vec[1];
01159        p1->r.p[2] = p1->r.p[2]-2*vec[2];
01160 
01161    /*  This can show the folded position after reflection      
01162        memcpy(folded_pos, p1->r.p, 3*sizeof(double));
01163        memcpy(img, p1->l.i, 3*sizeof(int));
01164        fold_position(folded_pos, img);
01165        printf("position after reflection %f %f %f\n",folded_pos[0], folded_pos[1], folded_pos[2]); */
01166 
01167        /* vec seams to be the vector that points from the wall to the particle*/
01168        /* now normalize it */ 
01169        if ( reflecting==1 ) {
01170          vec[0] /= norm;
01171          vec[1] /= norm;
01172          vec[2] /= norm;
01173          /* calculating scalar product - reusing var norm */
01174          norm = vec[0] *  p1->m.v[0] + vec[1] * p1->m.v[1] + vec[2] * p1->m.v[2];
01175          /* now add twice the normal component to the velcity */
01176           p1->m.v[0] = p1->m.v[0]-2*vec[0]*norm; /* norm is still the scalar product! */
01177           p1->m.v[1] = p1->m.v[1]-2*vec[1]*norm;
01178           p1->m.v[2] = p1->m.v[2]-2*vec[2]*norm;
01179        } else if (reflecting == 2) {
01180          /* if bounce back, invert velocity */
01181           p1->m.v[0] =-p1->m.v[0]; /* norm is still the scalar product! */
01182           p1->m.v[1] =-p1->m.v[1];
01183           p1->m.v[2] =-p1->m.v[2];
01184 
01185        }
01186 
01187 }
01188 
01189 void add_constraints_forces(Particle *p1)
01190 {
01191   if (n_constraints==0)
01192    return;
01193   int n, j;
01194   double dist, vec[3], force[3], torque1[3], torque2[3];
01195 
01196   IA_parameters *ia_params;
01197   char *errtxt;
01198   double folded_pos[3];
01199   int img[3];
01200 
01201   /* fold the coordinate[2] of the particle */
01202   memcpy(folded_pos, p1->r.p, 3*sizeof(double));
01203   memcpy(img, p1->l.i, 3*sizeof(int));
01204   fold_position(folded_pos, img);
01205 
01206   for(n=0;n<n_constraints;n++) {
01207     ia_params=get_ia_param(p1->p.type, (&constraints[n].part_rep)->p.type);
01208     dist=0.;
01209     for (j = 0; j < 3; j++) {
01210       force[j] = 0;
01211 #ifdef ROTATION
01212       torque1[j] = torque2[j] = 0;
01213 #endif
01214     }
01215 
01216     switch(constraints[n].type) {
01217     case CONSTRAINT_WAL: 
01218       if(checkIfInteraction(ia_params)) {
01219         calculate_wall_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.wal, &dist, vec); 
01220         if ( dist > 0 ) {
01221           calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01222                                      ia_params,vec,dist,dist*dist, force,
01223                                      torque1, torque2);
01224         }
01225         else if ( dist <= 0 && constraints[n].c.wal.penetrable == 1 ) {
01226           if ( dist < 0 ) {
01227             calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01228                                      ia_params,vec,-1.0*dist,dist*dist, force,
01229                                      torque1, torque2);
01230           }
01231         }
01232         else {
01233     if(constraints[n].c.wal.reflecting){
01234       reflect_particle(p1, &(vec[0]), constraints[n].c.wal.reflecting);
01235     } else {
01236           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01237           ERROR_SPRINTF(errtxt, "{061 wall constraint %d violated by particle %d} ", n, p1->p.identity);
01238     }
01239         }
01240       }
01241       break;
01242 
01243     case CONSTRAINT_SPH:
01244       if(checkIfInteraction(ia_params)) {
01245         calculate_sphere_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.sph, &dist, vec); 
01246         if ( dist > 0 ) {
01247           calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01248                                      ia_params,vec,dist,dist*dist, force,
01249                                      torque1, torque2);
01250         }
01251         else if ( dist <= 0 && constraints[n].c.sph.penetrable == 1 ) {
01252           if ( dist < 0 ) {
01253             calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01254                                      ia_params,vec,-1.0*dist,dist*dist, force,
01255                                      torque1, torque2);
01256           }
01257         }
01258         else {
01259     if(constraints[n].c.sph.reflecting){
01260       reflect_particle(p1, &(vec[0]), constraints[n].c.sph.reflecting);
01261     } else {
01262           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01263           ERROR_SPRINTF(errtxt, "{062 sphere constraint %d violated by particle %d} ", n, p1->p.identity);
01264     }
01265         }
01266       }
01267       break;
01268     
01269     case CONSTRAINT_CYL: 
01270       if(checkIfInteraction(ia_params)) {
01271         calculate_cylinder_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.cyl, &dist, vec); 
01272         if ( dist > 0 ) {
01273           calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01274                                      ia_params,vec,dist,dist*dist, force,
01275                                      torque1, torque2);
01276         }
01277         else if ( dist <= 0 && constraints[n].c.cyl.penetrable == 1 ) {
01278           if ( dist < 0 ) {
01279             calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01280                                      ia_params,vec,-1.0*dist,dist*dist, force,
01281                                      torque1, torque2);
01282           }
01283         }
01284         else {
01285     if(constraints[n].c.cyl.reflecting){
01286       reflect_particle(p1, &(vec[0]), constraints[n].c.cyl.reflecting);
01287     } else {
01288           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01289           ERROR_SPRINTF(errtxt, "{063 cylinder constraint %d violated by particle %d} ", n, p1->p.identity);
01290     }
01291         }
01292       }
01293       break;
01294     
01295     case CONSTRAINT_RHOMBOID: 
01296       if(checkIfInteraction(ia_params)) {
01297         calculate_rhomboid_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rhomboid, &dist, vec); 
01298         if ( dist > 0 ) {
01299           calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01300                                      ia_params,vec,dist,dist*dist, force,
01301                                      torque1, torque2);
01302         }
01303         else if ( dist <= 0 && constraints[n].c.rhomboid.penetrable == 1 ) {
01304           if ( dist < 0 ) {
01305             calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01306                                      ia_params,vec,-1.0*dist,dist*dist, force,
01307                                      torque1, torque2);
01308           }
01309         }
01310         else {
01311     if(constraints[n].c.rhomboid.reflecting){
01312       reflect_particle(p1, &(vec[0]), constraints[n].c.rhomboid.reflecting);
01313     } else {
01314           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01315           ERROR_SPRINTF(errtxt, "{063 rhomboid constraint %d violated by particle %d} ", n, p1->p.identity);
01316     }
01317         }
01318       }
01319       break;
01320         
01321     case CONSTRAINT_MAZE: 
01322       if(checkIfInteraction(ia_params)) {
01323         calculate_maze_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.maze, &dist, vec); 
01324         if ( dist > 0 ) {
01325           calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01326                                      ia_params,vec,dist,dist*dist, force,
01327                                      torque1, torque2);
01328         }
01329         else if ( dist <= 0 && constraints[n].c.maze.penetrable == 1 ) {
01330           if ( dist < 0 ) {
01331             calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01332                                      ia_params,vec,-1.0*dist,dist*dist, force,
01333                                      torque1, torque2);
01334           }
01335         }
01336         else {
01337           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01338           ERROR_SPRINTF(errtxt, "{064 maze constraint %d violated by particle %d} ", n, p1->p.identity);
01339         }
01340       }
01341       break;
01342 
01343     case CONSTRAINT_PORE: 
01344       if(checkIfInteraction(ia_params)) {
01345         calculate_pore_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.pore, &dist, vec); 
01346         if ( dist >= 0 ) {
01347           calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01348                                      ia_params,vec,dist,dist*dist, force,
01349                                      torque1, torque2);
01350         }
01351         else {
01352     if(constraints[n].c.pore.reflecting){
01353       reflect_particle(p1, &(vec[0]), constraints[n].c.pore.reflecting);
01354     } else {
01355           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01356           ERROR_SPRINTF(errtxt, "{063 pore constraint %d violated by particle %d} ", n, p1->p.identity);
01357         }
01358       }
01359       }
01360       break;
01361         
01362       /* electrostatic "constraints" */
01363     case CONSTRAINT_ROD:
01364       add_rod_force(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rod);
01365       break;
01366 
01367     case CONSTRAINT_PLATE:
01368       add_plate_force(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.plate);
01369       break;
01370       
01371 #ifdef DIPOLES
01372     case CONSTRAINT_EXT_MAGN_FIELD:
01373       add_ext_magn_field_force(p1, &constraints[n].c.emfield);
01374       break;
01375 #endif
01376     
01377     case CONSTRAINT_PLANE:
01378      if(checkIfInteraction(ia_params)) {
01379         calculate_plane_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.plane, &dist, vec); 
01380         if (dist > 0) {
01381             calc_non_bonded_pair_force(p1, &constraints[n].part_rep,
01382                                        ia_params,vec,dist,dist*dist, force,
01383                                        torque1, torque2);
01384 #ifdef TUNABLE_SLIP
01385             add_tunable_slip_pair_force(p1, &constraints[n].part_rep,ia_params,vec,dist,force);
01386 #endif
01387         }
01388         else {
01389           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01390           ERROR_SPRINTF(errtxt, "{063 plane constraint %d violated by particle %d} ", n, p1->p.identity);
01391         }
01392       }
01393       break;
01394     }
01395     for (j = 0; j < 3; j++) {
01396       p1->f.f[j] += force[j];
01397       constraints[n].part_rep.f.f[j] -= force[j];
01398 #ifdef ROTATION
01399       p1->f.torque[j] += torque1[j];
01400       constraints[n].part_rep.f.torque[j] += torque2[j];
01401 #endif
01402     }
01403   }
01404 }
01405 
01406 double add_constraints_energy(Particle *p1)
01407 {
01408   int n, type;
01409   double dist, vec[3];
01410   double nonbonded_en, coulomb_en, magnetic_en;
01411   IA_parameters *ia_params;
01412   char *errtxt;
01413   double folded_pos[3];
01414   int img[3];
01415 
01416   /* fold the coordinate[2] of the particle */
01417   memcpy(folded_pos, p1->r.p, 3*sizeof(double));
01418   memcpy(img, p1->l.i, 3*sizeof(int));
01419   fold_position(folded_pos, img);
01420   for(n=0;n<n_constraints;n++) { 
01421     ia_params = get_ia_param(p1->p.type, (&constraints[n].part_rep)->p.type);
01422     nonbonded_en = 0.;
01423     coulomb_en   = 0.;
01424     magnetic_en = 0.;
01425 
01426     dist=0.;
01427     switch(constraints[n].type) {
01428     case CONSTRAINT_WAL: 
01429       if(checkIfInteraction(ia_params)) {
01430         calculate_wall_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.wal, &dist, vec); 
01431         if ( dist > 0 ) {
01432           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01433                                                      ia_params, vec, dist, dist*dist);
01434         }
01435         else if ( dist <= 0 && constraints[n].c.wal.penetrable == 1 ) {
01436           if ( dist < 0 ) {
01437           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01438                                                      ia_params, vec, -1.0*dist, dist*dist);
01439           }
01440         }
01441         else {
01442           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01443           ERROR_SPRINTF(errtxt, "{065 wall constraint %d violated by particle %d} ", n, p1->p.identity);
01444         }
01445       }
01446       break;
01447         
01448     case CONSTRAINT_SPH: 
01449       if(checkIfInteraction(ia_params)) {
01450         calculate_sphere_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.sph, &dist, vec); 
01451         if ( dist > 0 ) {
01452           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01453                                                      ia_params, vec, dist, dist*dist);
01454         }
01455         else if ( dist <= 0 && constraints[n].c.sph.penetrable == 1 ) {
01456           if ( dist < 0 ) {
01457           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01458                                                      ia_params, vec, -1.0*dist, dist*dist);
01459           }
01460         }
01461         else {
01462           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01463           ERROR_SPRINTF(errtxt, "{066 sphere constraint %d violated by particle %d} ", n, p1->p.identity);
01464         }
01465       }
01466       break;
01467         
01468     case CONSTRAINT_CYL: 
01469       if(checkIfInteraction(ia_params)) {
01470         calculate_cylinder_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.cyl, &dist , vec); 
01471         if ( dist > 0 ) {
01472           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01473                                                      ia_params, vec, dist, dist*dist);
01474 
01475         }
01476         else if ( dist <= 0 && constraints[n].c.cyl.penetrable == 1 ) {
01477           if ( dist < 0 ) {
01478           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01479                                                      ia_params, vec, -1.0*dist, dist*dist);
01480           }
01481         }
01482         else {
01483           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01484           ERROR_SPRINTF(errtxt, "{067 cylinder constraint %d violated by particle %d} ", n, p1->p.identity);
01485         }
01486       }
01487       break;
01488         
01489     case CONSTRAINT_RHOMBOID: 
01490       if(checkIfInteraction(ia_params)) {
01491         calculate_rhomboid_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rhomboid, &dist , vec); 
01492         if ( dist > 0 ) {
01493           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01494                                                      ia_params, vec, dist, dist*dist);
01495 
01496         }
01497         else if ( dist <= 0 && constraints[n].c.rhomboid.penetrable == 1 ) {
01498           if ( dist < 0 ) {
01499           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01500                                                      ia_params, vec, -1.0*dist, dist*dist);
01501           }
01502         }
01503         else {
01504           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01505           ERROR_SPRINTF(errtxt, "{067 cylinder constraint %d violated by particle %d} ", n, p1->p.identity);
01506         }
01507       }
01508       break;
01509 
01510     case CONSTRAINT_MAZE: 
01511       if(checkIfInteraction(ia_params)) {
01512         calculate_maze_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.maze, &dist, vec); 
01513         if ( dist > 0 ) {
01514           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01515                                                      ia_params, vec, dist, dist*dist);
01516         }
01517         else if ( dist <= 0 && constraints[n].c.maze.penetrable == 1 ) {
01518           if ( dist < 0 ) {
01519           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01520                                                      ia_params, vec, -1.0*dist, dist*dist);
01521           }
01522         }
01523         else {
01524           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01525           ERROR_SPRINTF(errtxt, "{068 maze constraint %d violated by particle %d} ", n, p1->p.identity);
01526         }
01527       }
01528       break;
01529 
01530     case CONSTRAINT_PORE: 
01531       if(checkIfInteraction(ia_params)) {
01532         calculate_pore_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.pore, &dist , vec); 
01533         if ( dist > 0 ) {
01534           nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep,
01535                                                      ia_params, vec, dist, dist*dist);
01536 
01537         }
01538         else {
01539           errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
01540           ERROR_SPRINTF(errtxt, "{067 pore constraint %d violated by particle %d} ", n, p1->p.identity);
01541         }
01542       }
01543       break;
01544 
01545     case CONSTRAINT_ROD:
01546       coulomb_en = rod_energy(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rod);
01547       break;
01548 
01549     case CONSTRAINT_PLATE:
01550       coulomb_en = plate_energy(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.plate);
01551       break;
01552     case CONSTRAINT_EXT_MAGN_FIELD:
01553       magnetic_en = ext_magn_field_energy(p1, &constraints[n].c.emfield);
01554       break;
01555     }
01556 
01557     if (energy.n_coulomb > 0)
01558       energy.coulomb[0] += coulomb_en;
01559     
01560     if (energy.n_dipolar > 0)
01561       energy.dipolar[0] += magnetic_en;
01562 
01563     type = (&constraints[n].part_rep)->p.type;
01564     if (type >= 0)
01565       *obsstat_nonbonded(&energy, p1->p.type, type) += nonbonded_en;
01566   }
01567   return 0.;
01568 }
01569 
01570 #endif
01571