/* Copyright (C) 2010,2011,2012,2013 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group This file is part of ESPResSo. ESPResSo is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ESPResSo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** \file constraint.c Implementation of \ref constraint.h "constraint.h", here it's just the parsing stuff. */ #include "constraint.h" #include "energy.h" #include "forces.h" #include "tunable_slip.h" // for the charged rod "constraint" #define C_GAMMA 0.57721566490153286060651209008 int reflection_happened; #ifdef CONSTRAINTS int n_constraints = 0; Constraint *constraints = NULL; Constraint *generate_constraint() { n_constraints++; constraints = realloc(constraints,n_constraints*sizeof(Constraint)); constraints[n_constraints-1].type = CONSTRAINT_NONE; constraints[n_constraints-1].part_rep.p.identity = -n_constraints; return &constraints[n_constraints-1]; } void init_constraint_forces() { int n, i; for (n = 0; n < n_constraints; n++) for (i = 0; i < 3; i++) constraints[n].part_rep.f.f[i] = 0; } static double sign(double x) { if (x > 0) return 1.; else return -1; } static double max(double x1, double x2) { return x1>x2?x1:x2; } void calculate_wall_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_wall *c, double *dist, double *vec) { int i; *dist = -c->d; for(i=0;i<3;i++) *dist += ppos[i]*c->n[i]; for(i=0;i<3;i++) vec[i] = c->n[i] * *dist; } void calculate_sphere_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_sphere *c, double *dist, double *vec) { int i; double fac, c_dist; c_dist=0.0; for(i=0;i<3;i++) { vec[i] = c->pos[i] - ppos[i]; c_dist += SQR(vec[i]); } c_dist = sqrt(c_dist); if ( c->direction == -1 ) { /* apply force towards inside the sphere */ *dist = c->rad - c_dist; fac = *dist / c_dist; for(i=0;i<3;i++) vec[i] *= fac; } else { /* apply force towards outside the sphere */ *dist = c_dist - c->rad; fac = *dist / c_dist; for(i=0;i<3;i++) vec[i] *= -fac; } } void calculate_maze_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_maze *c, double *dist, double *vec) { int i,min_axis,cursph[3],dim; double diasph,fac,c_dist,sph_dist,cyl_dist,temp_dis; double sph_vec[3],cyl_vec[3]; dim=(int) c->dim; diasph = box_l[0]/c->nsphere; /* First determine the distance to the sphere */ c_dist=0.0; for(i=0;i<3;i++) { cursph[i] = (int) (ppos[i]/diasph); sph_vec[i] = (cursph[i]+0.5) * diasph - (ppos[i]); c_dist += SQR(sph_vec[i]); } c_dist = sqrt(c_dist); sph_dist = c->sphrad - c_dist; fac = sph_dist / c_dist; for(i=0;i<3;i++) cyl_vec[i] = sph_vec[i]; for(i=0;i<3;i++) sph_vec[i] *= fac; /* Now calculate the cylinder stuff */ /* have to check all 3 cylinders */ min_axis=2; cyl_dist=sqrt(cyl_vec[0]*cyl_vec[0]+cyl_vec[1]*cyl_vec[1]); if(dim > 0 ){ temp_dis=sqrt(cyl_vec[0]*cyl_vec[0]+cyl_vec[2]*cyl_vec[2]); if ( temp_dis < cyl_dist) { min_axis=1; cyl_dist=temp_dis; } if(dim > 1 ){ temp_dis=sqrt(cyl_vec[1]*cyl_vec[1]+cyl_vec[2]*cyl_vec[2]); if ( temp_dis < cyl_dist) { min_axis=0; cyl_dist=temp_dis; } } } cyl_vec[min_axis]=0.; c_dist=cyl_dist; cyl_dist = c->cylrad - c_dist; fac = cyl_dist / c_dist; for(i=0;i<3;i++) cyl_vec[i] *= fac; /* Now decide between cylinder and sphere */ if ( sph_dist > 0 ) { if ( sph_dist>cyl_dist ) { *dist = sph_dist; for(i=0;i<3;i++) vec[i] = sph_vec[i]; } else { *dist = cyl_dist; for(i=0;i<3;i++) vec[i] = cyl_vec[i]; } } else { *dist = cyl_dist; for(i=0;i<3;i++) vec[i] = cyl_vec[i]; } } void calculate_cylinder_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_cylinder *c, double *dist, double *vec) { int i; double d_per,d_par,d_real,d_per_vec[3],d_par_vec[3],d_real_vec[3]; d_real = 0.0; for(i=0;i<3;i++) { d_real_vec[i] = ppos[i] - c->pos[i]; d_real += SQR(d_real_vec[i]); } d_real = sqrt(d_real); d_par=0.; for(i=0;i<3;i++) { d_par += (d_real_vec[i] * c->axis[i]); } for(i=0;i<3;i++) { d_par_vec[i] = d_par * c->axis[i] ; d_per_vec[i] = ppos[i] - (c->pos[i] + d_par_vec[i]) ; } d_per=sqrt(SQR(d_real)-SQR(d_par)); d_par = fabs(d_par) ; if ( c->direction == -1 ) { /*apply force towards inside cylinder */ d_per = c->rad - d_per ; d_par = c->length - d_par; if (d_per < d_par ) { *dist = d_per ; for (i=0; i<3;i++) { vec[i]= -d_per_vec[i] * d_per / (c->rad - d_per) ; } } else { *dist = d_par ; for (i=0; i<3;i++) { vec[i]= -d_par_vec[i] * d_par / (c->length - d_par) ; } } } else { /*apply force towards outside cylinder */ d_per = d_per - c->rad ; d_par = d_par - c->length ; if (d_par < 0 ) { *dist = d_per ; for (i=0; i<3;i++) { vec[i]= d_per_vec[i] * d_per / (d_per + c->rad) ; } } else if ( d_per < 0) { *dist = d_par ; for (i=0; i<3;i++) { vec[i]= d_par_vec[i] * d_par / (d_par + c->length) ; } } else { *dist = sqrt( SQR(d_par) + SQR(d_per)) ; for (i=0; i<3;i++) { vec[i]= d_per_vec[i] * d_per / (d_per + c->rad) + d_par_vec[i] * d_par / (d_par + c->length) ; } } } } void calculate_rhomboid_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_rhomboid *c, double *dist, double *vec) { double axb[3], bxc[3], axc[3]; double A, B, C; double a_dot_bxc, b_dot_axc, c_dot_axb; double tmp; double d; //calculate a couple of vectors and scalars that are going to be used frequently axb[0] = c->a[1]*c->b[2] - c->a[2]*c->b[1]; axb[1] = c->a[2]*c->b[0] - c->a[0]*c->b[2]; axb[2] = c->a[0]*c->b[1] - c->a[1]*c->b[0]; bxc[0] = c->b[1]*c->c[2] - c->b[2]*c->c[1]; bxc[1] = c->b[2]*c->c[0] - c->b[0]*c->c[2]; bxc[2] = c->b[0]*c->c[1] - c->b[1]*c->c[0]; axc[0] = c->a[1]*c->c[2] - c->a[2]*c->c[1]; axc[1] = c->a[2]*c->c[0] - c->a[0]*c->c[2]; axc[2] = c->a[0]*c->c[1] - c->a[1]*c->c[0]; a_dot_bxc = c->a[0]*bxc[0] + c->a[1]*bxc[1] + c->a[2]*bxc[2]; b_dot_axc = c->b[0]*axc[0] + c->b[1]*axc[1] + c->b[2]*axc[2]; c_dot_axb = c->c[0]*axb[0] + c->c[1]*axb[1] + c->c[2]*axb[2]; //represent the distance from pos to ppos as a linear combination of the edge vectors. A = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2]; A /= a_dot_bxc; B = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2]; B /= b_dot_axc; C = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2]; C /= c_dot_axb; //the coefficients tell whether ppos lies within the cone defined by pos and the adjacent edges if(A <= 0 && B <= 0 && C <= 0) { vec[0] = ppos[0]-c->pos[0]; vec[1] = ppos[1]-c->pos[1]; vec[2] = ppos[2]-c->pos[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for cone at pos+a 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(A >= 0 && B <= 0 && C <= 0) { vec[0] = ppos[0]-c->pos[0]-c->a[0]; vec[1] = ppos[1]-c->pos[1]-c->a[1]; vec[2] = ppos[2]-c->pos[2]-c->a[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for cone at pos+b 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(A <= 0 && B >= 0 && C <= 0) { vec[0] = ppos[0]-c->pos[0]-c->b[0]; vec[1] = ppos[1]-c->pos[1]-c->b[1]; vec[2] = ppos[2]-c->pos[2]-c->b[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for cone at pos+c 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(A <= 0 && B <= 0 && C >= 0) { vec[0] = ppos[0]-c->pos[0]-c->c[0]; vec[1] = ppos[1]-c->pos[1]-c->c[1]; vec[2] = ppos[2]-c->pos[2]-c->c[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for cone at pos+a+b 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(A >= 0 && B >= 0 && C <= 0) { vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0]; vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1]; vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for cone at pos+a+c 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(A >= 0 && B <= 0 && C >= 0) { vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->c[0]; vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->c[1]; vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->c[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for cone at pos+a+c 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(A <= 0 && B >= 0 && C >= 0) { vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0]; vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1]; vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for cone at pos+a+b+c 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(A >= 0 && B >= 0 && C >= 0) { vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0]-c->c[0]; vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1]-c->c[1]; vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2]-c->c[2]; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos, a B = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2]; B /= b_dot_axc; C = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2]; C /= c_dot_axb; if(B <= 0 && C <= 0) { 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]; tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2]; vec[0] = ppos[0]-c->pos[0] - c->a[0]*tmp; vec[1] = ppos[1]-c->pos[1] - c->a[1]*tmp; vec[2] = ppos[2]-c->pos[2] - c->a[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos, b A = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2]; A /= a_dot_bxc; C = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2]; C /= c_dot_axb; if(A <= 0 && C <= 0) { 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]; tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2]; vec[0] = ppos[0]-c->pos[0] - c->b[0]*tmp; vec[1] = ppos[1]-c->pos[1] - c->b[1]*tmp; vec[2] = ppos[2]-c->pos[2] - c->b[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos, c A = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2]; A /= a_dot_bxc; B = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2]; B /= b_dot_axc; if(A <= 0 && B <= 0) { 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]; tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2]; vec[0] = ppos[0]-c->pos[0] - c->c[0]*tmp; vec[1] = ppos[1]-c->pos[1] - c->c[1]*tmp; vec[2] = ppos[2]-c->pos[2] - c->c[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+a, b 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]; A /= a_dot_bxc; 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]; C /= c_dot_axb; if(A >= 0 && C <= 0) { 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]; tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2]; vec[0] = ppos[0]-c->pos[0]-c->a[0] - c->b[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->a[1] - c->b[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->a[2] - c->b[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+a, c 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; if(A >= 0 && B <= 0) { 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]; tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2]; vec[0] = ppos[0]-c->pos[0]-c->a[0] - c->c[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->a[1] - c->c[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->a[2] - c->c[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+b+c, c 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; if(A <= 0 && B >= 0) { 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]; tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2]; vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0] - c->c[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1] - c->c[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2] - c->c[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+b+c, b 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]; A /= a_dot_bxc; 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]; C /= c_dot_axb; if(A <= 0 && C >= 0) { 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]; tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2]; vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0] - c->b[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1] - c->b[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2] - c->b[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+b+c, a 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(B >= 0 && C >= 0) { 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]; tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2]; vec[0] = ppos[0]-c->pos[0]-c->b[0]-c->c[0] - c->a[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->b[1]-c->c[1] - c->a[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->b[2]-c->c[2] - c->a[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+a+b, a 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(B >= 0 && C <= 0) { 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]; tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2]; vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0] - c->a[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1] - c->a[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2] - c->a[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+a+b, c 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]; A /= a_dot_bxc; 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]; B /= b_dot_axc; if(A >= 0 && B >= 0) { 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]; tmp /= c->c[0]*c->c[0] + c->c[1]*c->c[1] + c->c[2]*c->c[2]; vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->b[0] - c->c[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->b[1] - c->c[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->b[2] - c->c[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+a+c, a 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]; B /= b_dot_axc; 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]; C /= c_dot_axb; if(B <= 0 && C >= 0) { 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]; tmp /= c->a[0]*c->a[0] + c->a[1]*c->a[1] + c->a[2]*c->a[2]; vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->c[0] - c->a[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->c[1] - c->a[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->c[2] - c->a[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for prism at edge pos+a+c, b 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]; A /= a_dot_bxc; 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]; C /= c_dot_axb; if(A >= 0 && C >= 0) { 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]; tmp /= c->b[0]*c->b[0] + c->b[1]*c->b[1] + c->b[2]*c->b[2]; vec[0] = ppos[0]-c->pos[0]-c->a[0]-c->c[0] - c->b[0]*tmp; vec[1] = ppos[1]-c->pos[1]-c->a[1]-c->c[1] - c->b[1]*tmp; vec[2] = ppos[2]-c->pos[2]-c->a[2]-c->c[2] - c->b[2]*tmp; *dist = c->direction * sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); return; } //check for face with normal -axb *dist = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2]; *dist *= -1.; if(*dist >= 0) { tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] ); *dist /= tmp; vec[0] = -*dist * axb[0]/tmp; vec[1] = -*dist * axb[1]/tmp; vec[2] = -*dist * axb[2]/tmp; *dist *= c->direction; return; } //calculate distance to face with normal axc *dist = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2]; if(*dist >= 0) { tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] ); *dist /= tmp; vec[0] = *dist * axc[0]/tmp; vec[1] = *dist * axc[1]/tmp; vec[2] = *dist * axc[2]/tmp; *dist *= c->direction; return; } //calculate distance to face with normal -bxc *dist = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2]; *dist *= -1.; if(*dist >= 0) { tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] ); *dist /= tmp; vec[0] = -*dist * bxc[0]/tmp; vec[1] = -*dist * bxc[1]/tmp; vec[2] = -*dist * bxc[2]/tmp; *dist *= c->direction; return; } //calculate distance to face with normal axb *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]; if(*dist >= 0) { tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] ); *dist /= tmp; vec[0] = *dist * axb[0]/tmp; vec[1] = *dist * axb[1]/tmp; vec[2] = *dist * axb[2]/tmp; *dist *= c->direction; return; } //calculate distance to face with normal -axc *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]; *dist *= -1.; if(*dist >= 0) { tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] ); *dist /= tmp; vec[0] = -*dist * axc[0]/tmp; vec[1] = -*dist * axc[1]/tmp; vec[2] = -*dist * axc[2]/tmp; *dist *= c->direction; return; } //calculate distance to face with normal bxc *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]; if(*dist >= 0) { tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] ); *dist /= tmp; vec[0] = *dist * bxc[0]/tmp; vec[1] = *dist * bxc[1]/tmp; vec[2] = *dist * bxc[2]/tmp; *dist *= c->direction; return; } //ppos lies within rhomboid. Find nearest wall for interaction. //check for face with normal -axb *dist = (ppos[0]-c->pos[0])*axb[0] + (ppos[1]-c->pos[1])*axb[1] + (ppos[2]-c->pos[2])*axb[2]; *dist *= -1.; tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] ); *dist /= tmp; vec[0] = -*dist * axb[0]/tmp; vec[1] = -*dist * axb[1]/tmp; vec[2] = -*dist * axb[2]/tmp; *dist *= c->direction; //calculate distance to face with normal axc d = (ppos[0]-c->pos[0])*axc[0] + (ppos[1]-c->pos[1])*axc[1] + (ppos[2]-c->pos[2])*axc[2]; tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] ); d /= tmp; if(abs(d) < abs(*dist)) { vec[0] = d * axc[0]/tmp; vec[1] = d * axc[1]/tmp; vec[2] = d * axc[2]/tmp; *dist = c->direction * d; } //calculate distance to face with normal -bxc d = (ppos[0]-c->pos[0])*bxc[0] + (ppos[1]-c->pos[1])*bxc[1] + (ppos[2]-c->pos[2])*bxc[2]; d *= -1.; tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] ); d /= tmp; if(abs(d) < abs(*dist)) { vec[0] = -d * bxc[0]/tmp; vec[1] = -d * bxc[1]/tmp; vec[2] = -d * bxc[2]/tmp; *dist = c->direction * d; } //calculate distance to face with normal axb 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]; tmp = sqrt( axb[0]*axb[0] + axb[1]*axb[1] + axb[2]*axb[2] ); d /= tmp; if(abs(d) < abs(*dist)) { vec[0] = d * axb[0]/tmp; vec[1] = d * axb[1]/tmp; vec[2] = d * axb[2]/tmp; *dist = c->direction * d; } //calculate distance to face with normal -axc 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]; d *= -1.; tmp = sqrt( axc[0]*axc[0] + axc[1]*axc[1] + axc[2]*axc[2] ); d /= tmp; if(abs(d) < abs(*dist)) { vec[0] = -d * axc[0]/tmp; vec[1] = -d * axc[1]/tmp; vec[2] = -d * axc[2]/tmp; *dist = c->direction * d; } //calculate distance to face with normal bxc 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]; tmp = sqrt( bxc[0]*bxc[0] + bxc[1]*bxc[1] + bxc[2]*bxc[2] ); d /= tmp; if(abs(d) < abs(*dist)) { vec[0] = d * bxc[0]/tmp; vec[1] = d * bxc[1]/tmp; vec[2] = d * bxc[2]/tmp; *dist = c->direction * d; } } void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_pore *c, double *dist, double *vec) { int i; double c_dist[3]; /* cartesian distance from pore center */ double z , r; /* cylindrical coordinates, coordinate system parallel to pore, origin at pore centera */ double z_vec[3], r_vec[3]; /* cartesian vectors that correspond to these coordinates */ double e_z[3], e_r[3]; /* unit vectors in the cylindrical coordinate system */ /* helper variables, for performance reasons should the be move the the * constraint struct*/ double slope, z_left, z_right; /* and another helper that is hopefully optmized out */ double norm; double c1_r, c1_z, c2_r, c2_z; double cone_vector_r, cone_vector_z, p1_r, p1_z, dist_vector_z, dist_vector_r, temp; slope = (c->rad_right - c->rad_left)/2./(c->length-c->smoothing_radius); /* compute the position relative to the center of the pore */ for(i=0;i<3;i++) { c_dist[i] = ppos[i] - c->pos[i]; } /* compute the component parallel to the pore axis */ z =0.; for(i=0;i<3;i++) { z += (c_dist[i] * c->axis[i]); } /* decompose the position into parallel and perpendicular to the axis */ r = 0.; for(i=0;i<3;i++) { z_vec[i] = z * c->axis[i]; r_vec[i] = c_dist[i] - z_vec[i]; r += r_vec[i]*r_vec[i]; } r = sqrt(r); /* calculate norm and unit vectors for both */ norm = 0; for(i=0;i<3;i++) norm += z_vec[i]*z_vec[i]; norm = sqrt(norm); for(i=0;i<3;i++) e_z[i] = c->axis[i]; norm = 0; for(i=0;i<3;i++) norm += r_vec[i]*r_vec[i]; norm = sqrt(norm); for(i=0;i<3;i++) e_r[i] = r_vec[i]/norm; /* c?_r/z and are the centers of the circles that are used to smooth * the entrance of the pore in cylindrical coordinates*/ c1_z = - (c->length - c->smoothing_radius); c2_z = + (c->length - c->smoothing_radius); z_left = c1_z - sign(slope) * sqrt(slope*slope/(1+slope*slope))*c->smoothing_radius; z_right = c2_z + sign(slope) * sqrt(slope*slope/(1+slope*slope))*c->smoothing_radius; c1_r = c->rad_left + slope * ( z_left + c->length ) + sqrt( c->smoothing_radius * c->smoothing_radius - SQR( z_left - c1_z ) ); c2_r = c->rad_left + slope * ( z_right + c->length ) + sqrt( c->smoothing_radius * c->smoothing_radius - SQR( z_right - c2_z ) ); c1_r = c->rad_left+c->smoothing_radius; c2_r = c->rad_right+c->smoothing_radius; /* Check if we are in the region of the left wall */ if (( (r >= c1_r) && (z <= c1_z) ) || ( ( z <= 0 ) && (r>=max(c1_r, c2_r)))) { dist_vector_z=-z - c->length; dist_vector_r=0; *dist = -z - c->length; for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } /* Check if we are in the region of the right wall */ if (( (r >= c2_r) && (z <= c2_z) ) || ( ( z >= 0 ) && (r>=max(c1_r, c2_r)))) { dist_vector_z=-z + c->length; dist_vector_r=0; *dist = +z - c->length; for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } /* check if the particle should feel the smoothed ends or the middle of the pore */ /* calculate aufpunkt in z direction first. */ /* the distance of the particle from the pore cylinder/cone calculated by projection on the * cone normal. Should be > 0 if particle is inside the pore */ cone_vector_z=1/sqrt(1+slope*slope); cone_vector_r=slope/sqrt(1+slope*slope); p1_r = c1_r+ ( (r-c1_r)*cone_vector_r + (z-c1_z)*cone_vector_z) * cone_vector_r; p1_z = c1_z+ ( (r-c1_r)*cone_vector_r + (z-c1_z)*cone_vector_z) * cone_vector_z; dist_vector_r = p1_r-r; dist_vector_z = p1_z-z; if ( p1_z>=c1_z && p1_z<=c2_z ) { if ( dist_vector_r <= 0 ) { if (z<0) { dist_vector_z=-z - c->length; dist_vector_r=0; *dist = -z - c->length; for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } else { dist_vector_z=-z + c->length; dist_vector_r=0; *dist = +z - c->length; for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } } temp=sqrt( dist_vector_r*dist_vector_r + dist_vector_z*dist_vector_z ); *dist=temp-c->smoothing_radius; dist_vector_r-=dist_vector_r/temp*c->smoothing_radius; dist_vector_z-=dist_vector_z/temp*c->smoothing_radius; for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } /* Check if we are in the range of the left smoothing circle */ if (p1_z <= c1_z ) { /* distance from the smoothing center */ norm = sqrt( (z - c1_z)*(z - c1_z) + (r - c1_r)*(r - c1_r) ); *dist = norm - c->smoothing_radius; dist_vector_r=(c->smoothing_radius/norm -1)*(r - c1_r); dist_vector_z=(c->smoothing_radius/norm - 1)*(z - c1_z); for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } /* Check if we are in the range of the right smoothing circle */ if (p1_z >= c2_z ) { norm = sqrt( (z - c2_z)*(z - c2_z) + (r - c2_r)*(r - c2_r) ); *dist = norm - c->smoothing_radius; dist_vector_r=(c->smoothing_radius/norm -1)*(r - c2_r); dist_vector_z=(c->smoothing_radius/norm - 1)*(z - c2_z); for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } exit(printf("should never be reached, z %f, r%f\n",z, r)); } void calculate_plane_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_plane *c, double *dist, double *vec) { int i; double c_dist_sqr,c_dist; c_dist_sqr=0.0; for(i=0;i<3;i++) { if(c->pos[i] >= 0) { vec[i] = c->pos[i] - ppos[i]; c_dist_sqr += SQR(vec[i]); }else{ vec[i] = 0.0; c_dist_sqr += SQR(vec[i]); } } c_dist = sqrt(c_dist_sqr); *dist = c_dist; for(i=0;i<3;i++) { vec[i] *= -1; } } void add_rod_force(Particle *p1, double ppos[3], Particle *c_p, Constraint_rod *c) { #ifdef ELECTROSTATICS int i; double fac, vec[2], c_dist_2; c_dist_2 = 0.0; for(i=0;i<2;i++) { vec[i] = ppos[i] - c->pos[i]; c_dist_2 += SQR(vec[i]); } if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->lambda != 0.0) { fac = 2*coulomb.prefactor*c->lambda*p1->p.q/c_dist_2; p1->f.f[0] += fac*vec[0]; p1->f.f[1] += fac*vec[1]; c_p->f.f[0] -= fac*vec[0]; c_p->f.f[1] -= fac*vec[1]; } #endif } double rod_energy(Particle *p1, double ppos[3], Particle *c_p, Constraint_rod *c) { #ifdef ELECTROSTATICS int i; double vec[2], c_dist_2; c_dist_2 = 0.0; for(i=0;i<2;i++) { vec[i] = ppos[i] - c->pos[i]; c_dist_2 += SQR(vec[i]); } if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->lambda != 0.0) return coulomb.prefactor*p1->p.q*c->lambda*(-log(c_dist_2*SQR(box_l_i[2])) + 2*(M_LN2 - C_GAMMA)); #endif return 0; } void add_plate_force(Particle *p1, double ppos[3], Particle *c_p, Constraint_plate *c) { #ifdef ELECTROSTATICS double f; if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->sigma != 0.0) { f = 2*M_PI*coulomb.prefactor*c->sigma*p1->p.q; if (ppos[2] < c->pos) f = -f; p1->f.f[2] += f; c_p->f.f[2] -= f; } #endif } double plate_energy(Particle *p1, double ppos[3], Particle *c_p, Constraint_plate *c) { #ifdef ELECTROSTATICS if (coulomb.prefactor != 0.0 && p1->p.q != 0.0 && c->sigma != 0.0) return -2*M_PI*coulomb.prefactor*c->sigma*p1->p.q*fabs(ppos[2] - c->pos); #endif return 0; } //ER void add_ext_magn_field_force(Particle *p1, Constraint_ext_magn_field *c) { #ifdef ROTATION #ifdef DIPOLES p1->f.torque[0] += p1->r.dip[1]*c->ext_magn_field[2]-p1->r.dip[2]*c->ext_magn_field[1]; p1->f.torque[1] += p1->r.dip[2]*c->ext_magn_field[0]-p1->r.dip[0]*c->ext_magn_field[2]; p1->f.torque[2] += p1->r.dip[0]*c->ext_magn_field[1]-p1->r.dip[1]*c->ext_magn_field[0]; #endif #endif } double ext_magn_field_energy(Particle *p1, Constraint_ext_magn_field *c) { #ifdef DIPOLES return -1.0 * scalar(c->ext_magn_field,p1->r.dip); #endif return 0; } //end ER void add_appl_volt_force(Particle *p1, double ppos[3], Constraint_appl_volt *c) { #ifdef ELECTROSTATICS double E, d; double x, y, z, r; d = 3.0; d = d/2; x = ppos[0]-5000.; y = ppos[1]-5000.; z = ppos[2]-5000.; r = sqrt(x*x+y*y); E = c->appl_volt[2]; if ( z < 0.5 && z > -0.5 && r < d ) { p1->f.f[2] += p1->p.q*E; } #endif } double appl_volt_energy(Particle *p1, double ppos[3], Constraint_appl_volt *c) { #ifdef ELECTROSTATICS // I haven't wasted time changing this part!! until finding the correct expression, maybe when we needed the right energy // just to avoid errors replace ext_elec_field with appl_volt return c->appl_volt[2]*c->appl_volt[2]; // these expressions for electrostatic energy are wrong! They should be something like: E*z #endif return 0; } void reflect_particle(Particle *p1, double *distance_vec, int reflecting) { double vec[3]; double norm; double folded_pos[3]; int img[3]; memcpy(folded_pos, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(folded_pos, img); memcpy(vec, distance_vec, 3*sizeof(double)); /* For Debugging your can show the folded coordinates of the particle before * and after the reflecting by uncommenting these lines */ // printf("position before reflection %f %f %f\n",folded_pos[0], folded_pos[1], folded_pos[2]); reflection_happened = 1; norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]); p1->r.p[0] = p1->r.p[0]-2*vec[0]; p1->r.p[1] = p1->r.p[1]-2*vec[1]; p1->r.p[2] = p1->r.p[2]-2*vec[2]; /* This can show the folded position after reflection memcpy(folded_pos, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(folded_pos, img); printf("position after reflection %f %f %f\n",folded_pos[0], folded_pos[1], folded_pos[2]); */ /* vec seams to be the vector that points from the wall to the particle*/ /* now normalize it */ if ( reflecting==1 ) { vec[0] /= norm; vec[1] /= norm; vec[2] /= norm; /* calculating scalar product - reusing var norm */ norm = vec[0] * p1->m.v[0] + vec[1] * p1->m.v[1] + vec[2] * p1->m.v[2]; /* now add twice the normal component to the velcity */ p1->m.v[0] = p1->m.v[0]-2*vec[0]*norm; /* norm is still the scalar product! */ p1->m.v[1] = p1->m.v[1]-2*vec[1]*norm; p1->m.v[2] = p1->m.v[2]-2*vec[2]*norm; } else if (reflecting == 2) { /* if bounce back, invert velocity */ p1->m.v[0] =-p1->m.v[0]; /* norm is still the scalar product! */ p1->m.v[1] =-p1->m.v[1]; p1->m.v[2] =-p1->m.v[2]; } } void add_constraints_forces(Particle *p1) { if (n_constraints==0) return; int n, j; double dist, vec[3], force[3], torque1[3], torque2[3]; IA_parameters *ia_params; char *errtxt; double folded_pos[3]; int img[3]; /* fold the coordinate[2] of the particle */ memcpy(folded_pos, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(folded_pos, img); for(n=0;np.type, (&constraints[n].part_rep)->p.type); dist=0.; for (j = 0; j < 3; j++) { force[j] = 0; #ifdef ROTATION torque1[j] = torque2[j] = 0; #endif } switch(constraints[n].type) { case CONSTRAINT_WAL: if(checkIfInteraction(ia_params)) { calculate_wall_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.wal, &dist, vec); if ( dist > 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,dist,dist*dist, force, torque1, torque2); } else if ( dist <= 0 && constraints[n].c.wal.penetrable == 1 ) { if ( dist < 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,-1.0*dist,dist*dist, force, torque1, torque2); } } else { if(constraints[n].c.wal.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.wal.reflecting); } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{061 wall constraint %d violated by particle %d} ", n, p1->p.identity); } } } break; case CONSTRAINT_SPH: if(checkIfInteraction(ia_params)) { calculate_sphere_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.sph, &dist, vec); if ( dist > 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,dist,dist*dist, force, torque1, torque2); } else if ( dist <= 0 && constraints[n].c.sph.penetrable == 1 ) { if ( dist < 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,-1.0*dist,dist*dist, force, torque1, torque2); } } else { if(constraints[n].c.sph.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.sph.reflecting); } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{062 sphere constraint %d violated by particle %d} ", n, p1->p.identity); } } } break; case CONSTRAINT_CYL: if(checkIfInteraction(ia_params)) { calculate_cylinder_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.cyl, &dist, vec); if ( dist > 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,dist,dist*dist, force, torque1, torque2); } else if ( dist <= 0 && constraints[n].c.cyl.penetrable == 1 ) { if ( dist < 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,-1.0*dist,dist*dist, force, torque1, torque2); } } else { if(constraints[n].c.cyl.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.cyl.reflecting); } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{063 cylinder constraint %d violated by particle %d} ", n, p1->p.identity); } } } break; case CONSTRAINT_RHOMBOID: if(checkIfInteraction(ia_params)) { calculate_rhomboid_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rhomboid, &dist, vec); if ( dist > 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,dist,dist*dist, force, torque1, torque2); } else if ( dist <= 0 && constraints[n].c.rhomboid.penetrable == 1 ) { if ( dist < 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,-1.0*dist,dist*dist, force, torque1, torque2); } } else { if(constraints[n].c.rhomboid.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.rhomboid.reflecting); } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{063 rhomboid constraint %d violated by particle %d} ", n, p1->p.identity); } } } break; case CONSTRAINT_MAZE: if(checkIfInteraction(ia_params)) { calculate_maze_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.maze, &dist, vec); if ( dist > 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,dist,dist*dist, force, torque1, torque2); } else if ( dist <= 0 && constraints[n].c.maze.penetrable == 1 ) { if ( dist < 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,-1.0*dist,dist*dist, force, torque1, torque2); } } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{064 maze constraint %d violated by particle %d} ", n, p1->p.identity); } } break; case CONSTRAINT_PORE: if(checkIfInteraction(ia_params)) { calculate_pore_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.pore, &dist, vec); if ( dist >= 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,dist,dist*dist, force, torque1, torque2); } else { if(constraints[n].c.pore.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.pore.reflecting); } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{063 pore constraint %d violated by particle %d} ", n, p1->p.identity); } } } break; /* electrostatic "constraints" */ case CONSTRAINT_ROD: add_rod_force(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rod); break; case CONSTRAINT_PLATE: add_plate_force(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.plate); break; #ifdef DIPOLES case CONSTRAINT_EXT_MAGN_FIELD: add_ext_magn_field_force(p1, &constraints[n].c.emfield); break; #endif case CONSTRAINT_APPL_VOLT: add_appl_volt_force(p1, folded_pos, &constraints[n].c.avolt); break; case CONSTRAINT_PLANE: if(checkIfInteraction(ia_params)) { calculate_plane_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.plane, &dist, vec); if (dist > 0) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, ia_params,vec,dist,dist*dist, force, torque1, torque2); #ifdef TUNABLE_SLIP add_tunable_slip_pair_force(p1, &constraints[n].part_rep,ia_params,vec,dist,force); #endif } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{063 plane constraint %d violated by particle %d} ", n, p1->p.identity); } } break; } for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; constraints[n].part_rep.f.f[j] -= force[j]; #ifdef ROTATION p1->f.torque[j] += torque1[j]; constraints[n].part_rep.f.torque[j] += torque2[j]; #endif } } } double add_constraints_energy(Particle *p1) { int n, type; double dist, vec[3]; double nonbonded_en, coulomb_en, magnetic_en; IA_parameters *ia_params; char *errtxt; double folded_pos[3]; int img[3]; /* fold the coordinate[2] of the particle */ memcpy(folded_pos, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(folded_pos, img); for(n=0;np.type, (&constraints[n].part_rep)->p.type); nonbonded_en = 0.; coulomb_en = 0.; magnetic_en = 0.; dist=0.; switch(constraints[n].type) { case CONSTRAINT_WAL: if(checkIfInteraction(ia_params)) { calculate_wall_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.wal, &dist, vec); if ( dist > 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, dist, dist*dist); } else if ( dist <= 0 && constraints[n].c.wal.penetrable == 1 ) { if ( dist < 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, -1.0*dist, dist*dist); } } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{065 wall constraint %d violated by particle %d} ", n, p1->p.identity); } } break; case CONSTRAINT_SPH: if(checkIfInteraction(ia_params)) { calculate_sphere_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.sph, &dist, vec); if ( dist > 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, dist, dist*dist); } else if ( dist <= 0 && constraints[n].c.sph.penetrable == 1 ) { if ( dist < 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, -1.0*dist, dist*dist); } } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{066 sphere constraint %d violated by particle %d} ", n, p1->p.identity); } } break; case CONSTRAINT_CYL: if(checkIfInteraction(ia_params)) { calculate_cylinder_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.cyl, &dist , vec); if ( dist > 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, dist, dist*dist); } else if ( dist <= 0 && constraints[n].c.cyl.penetrable == 1 ) { if ( dist < 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, -1.0*dist, dist*dist); } } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{067 cylinder constraint %d violated by particle %d} ", n, p1->p.identity); } } break; case CONSTRAINT_RHOMBOID: if(checkIfInteraction(ia_params)) { calculate_rhomboid_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rhomboid, &dist , vec); if ( dist > 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, dist, dist*dist); } else if ( dist <= 0 && constraints[n].c.rhomboid.penetrable == 1 ) { if ( dist < 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, -1.0*dist, dist*dist); } } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{067 cylinder constraint %d violated by particle %d} ", n, p1->p.identity); } } break; case CONSTRAINT_MAZE: if(checkIfInteraction(ia_params)) { calculate_maze_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.maze, &dist, vec); if ( dist > 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, dist, dist*dist); } else if ( dist <= 0 && constraints[n].c.maze.penetrable == 1 ) { if ( dist < 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, -1.0*dist, dist*dist); } } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{068 maze constraint %d violated by particle %d} ", n, p1->p.identity); } } break; case CONSTRAINT_PORE: if(checkIfInteraction(ia_params)) { calculate_pore_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.pore, &dist , vec); if ( dist > 0 ) { nonbonded_en = calc_non_bonded_pair_energy(p1, &constraints[n].part_rep, ia_params, vec, dist, dist*dist); } else { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{067 pore constraint %d violated by particle %d} ", n, p1->p.identity); } } break; case CONSTRAINT_ROD: coulomb_en = rod_energy(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.rod); break; case CONSTRAINT_PLATE: coulomb_en = plate_energy(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.plate); break; case CONSTRAINT_EXT_MAGN_FIELD: magnetic_en = ext_magn_field_energy(p1, &constraints[n].c.emfield); break; case CONSTRAINT_APPL_VOLT: coulomb_en = appl_volt_energy(p1, folded_pos, &constraints[n].c.avolt); break; } if (energy.n_coulomb > 0) energy.coulomb[0] += coulomb_en; if (energy.n_dipolar > 0) energy.dipolar[0] += magnetic_en; type = (&constraints[n].part_rep)->p.type; if (type >= 0) *obsstat_nonbonded(&energy, p1->p.type, type) += nonbonded_en; } return 0.; } #endif