inline int calc_area_force_local_complicated(Particle *p1, Particle *p2, Particle *p3, Bonded_ia_parameters *iaparams, double force1[3], double force2[3], double force3[3]) // more complicated approach { int k; double A, aa, uh[3], vh[3], rh[3], hn; double uu[3],vv[3]; get_mi_vector(uu, p2->r.p, p1->r.p); get_mi_vector(vv, p3->r.p, p1->r.p); for(k=0;k<3;k++) rh[k]=1.0/3.0 *(uu[k]+vv[k]); for(k=0;k<3;k++) uh[k]=rh[k]-uu[k]; for(k=0;k<3;k++) vh[k]=rh[k]-vv[k]; A=area_triangle_new(uu,vv); //printf("area %e uu %e %e %e vv %e %e %e\n", A, uu[0], uu[1], uu[2], vv[0], vv[1], vv[2]); aa=(A - iaparams->p.area_force_local.A0_l)/iaparams->p.area_force_local.A0_l; hn=normr(rh); for(k=0;k<3;k++) { force1[k] = iaparams->p.area_force_local.ka_l * aa * rh[k]/hn; } hn=normr(uh); for(k=0;k<3;k++) { force2[k] = iaparams->p.area_force_local.ka_l * aa * uh[k]/hn; } hn=normr(vh); for(k=0;k<3;k++) { force3[k] = iaparams->p.area_force_local.ka_l * aa * vh[k]/hn; } return 0; }
/** Computes the bending force (Dupin2007 eqn. 20 and 21) and adds this force to the particle forces (see \ref tclcommand_inter). @param p1,p2,p3 Pointers to particles of triangle 1. @param p2,p3,p4 Pointers to particles of triangle 2. (triangles have particles p2 and p3 in common) @param iaparams bending stiffness kb, initial rest angle phi0 (see \ref tclcommand_inter). @param force1 returns force on particles of triangle 1 @param force2 returns force on particles of triangle 2 (p1 += force1; p2 += 0.5*force1+0.5*force2; p3 += 0.5*force1+0.5*force2; p4 += force2; @return 0 */ inline int calc_bending_force(Particle *p2, Particle *p1, Particle *p3, Particle *p4, Bonded_ia_parameters *iaparams, double force1[3], double force2[2])// first-fold-then-the-same approach { double n1[3],n2[3],dn1,dn2,phi,aa,fac,penal; int k; double fp1[3],fp2[3],fp3[3],fp4[3]; #ifdef LEES_EDWARDS double vv[3]; #endif int img[3]; memcpy(fp1, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(fp1, img); memcpy(fp2, p2->r.p, 3*sizeof(double)); memcpy(img, p2->l.i, 3*sizeof(int)); fold_position(fp2, img); memcpy(fp3, p3->r.p, 3*sizeof(double)); memcpy(img, p3->l.i, 3*sizeof(int)); fold_position(fp3, img); memcpy(fp4, p4->r.p, 3*sizeof(double)); memcpy(img, p4->l.i, 3*sizeof(int)); fold_position(fp4, img); get_n_triangle(fp2,fp1,fp3,n1); dn1=normr(n1); get_n_triangle(fp2,fp3,fp4,n2); dn2=normr(n2); phi = angle_btw_triangles(fp1,fp2,fp3,fp4); if (iaparams->p.bending_force.phi0 < 0.001 || iaparams->p.bending_force.phi0 > 2*M_PI - 0.001) printf("bending_force.h, calc_bending_force: Resting angle is close to zero!!!\n"); aa = (phi-iaparams->p.bending_force.phi0)/iaparams->p.bending_force.phi0; fac = iaparams->p.bending_force.kb * aa; penal = (1+1/pow(10*(2*M_PI-phi),2) + 1/pow(10*(phi),2)); if (penal > 5.) penal = 5.; // fac = fac*penal; // This is to penalize the angles smaller than some threshold tr and also it penalizes angles greater than 2*Pi - tr. It prevents the objects to have negative angles. if (phi < 0.001 || phi > 2*M_PI - 0.001) printf("bending_force.h, calc_bending_force: Angle approaches 0 or 2*Pi\n"); for(k=0;k<3;k++) { force1[k]=fac * n1[k]/dn1; force2[k]=fac * n2[k]/dn2; } return 0; }
/** Computes the local area force (Dupin2007 eqn. 15) and adds this force to the particle forces (see \ref tclcommand_inter). @param p1,p2,p3 Pointers to triangle particles. @param iaparams elastic area modulus ka, initial area A0 (see \ref tclcommand_inter). @param force1 returns force of particle 1 @param force2 returns force of particle 2 @param force3 returns force of particle 3 @return 0 */ inline int calc_area_force_local(Particle *p1, Particle *p2, Particle *p3, Bonded_ia_parameters *iaparams, double force1[3], double force2[3], double force3[3]) //first-fold-then-the-same approach { int k; double A, aa, h[3], rh[3], hn; double p11[3],p22[3],p33[3]; int img[3]; memcpy(p11, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(p11, img); memcpy(p22, p2->r.p, 3*sizeof(double)); memcpy(img, p2->l.i, 3*sizeof(int)); fold_position(p22, img); memcpy(p33, p3->r.p, 3*sizeof(double)); memcpy(img, p3->l.i, 3*sizeof(int)); fold_position(p33, img); for(k=0;k<3;k++) h[k]=1.0/3.0 *(p11[k]+p22[k]+p33[k]); //volume+=A * -n[2]/dn * h[2]; A=area_triangle(p11,p22,p33); aa=(A - iaparams->p.area_force_local.A0_l)/iaparams->p.area_force_local.A0_l; //aminusb(3,h,p11,rh); // area_forces for each triangle node vecsub(h,p11,rh); // area_forces for each triangle node hn=normr(rh); for(k=0;k<3;k++) { force1[k] = iaparams->p.area_force_local.ka_l * aa * rh[k]/hn; //(&part1)->f.f[k]+=force[k]; } //aminusb(3,h,p22,rh); // area_forces for each triangle node vecsub(h,p22,rh); // area_forces for each triangle node hn=normr(rh); for(k=0;k<3;k++) { force2[k] = iaparams->p.area_force_local.ka_l * aa * rh[k]/hn; //(&part2)->f.f[k]+=force[k]; } //aminusb(3,h,p33,rh); // area_forces for each triangle node vecsub(h,p33,rh); // area_forces for each triangle node hn=normr(rh); for(k=0;k<3;k++) { force3[k] = iaparams->p.area_force_local.ka_l * aa * rh[k]/hn; //(&part3)->f.f[k]+=force[k]; } return 0; }
/** Computes the area of triangle between vectors P1 and P2, * by computing the crossproduct P1 x P2 and taking the half of its norm */ inline double area_triangle_new(double *P1, double *P2) { double area; double normal[3], n; //auxiliary variables vector_product(P1,P2,normal); n=normr(normal); area = 0.5*n; return area; }
bool IterativeSolvers::pcg(const IRCMatrix &A, Vector &x, const Vector &b, const Preconditioner &M) { /*! Solves Ax=b using the preconditioned conjugate gradient method. */ const idx N = x.getLength(); real resid(100.0); Vector p(N), z(N), q(N); real alpha; real normr(0); real normb = norm(b); real rho(0), rho_1(0), beta(0); Vector r = b - A * x; if (normb == 0.0) normb = 1; resid = norm(r) / normb; if (resid <= IterativeSolvers::toler) { IterativeSolvers::toler = resid; IterativeSolvers::maxIter = 0; return true; } // MAIN LOOP idx i = 1; for (; i <= IterativeSolvers::maxIter; i++) { M.solveMxb(z, r); rho = dot(r, z); if (i == 1) p = z; else { beta = rho / rho_1; aypx(beta, p, z); // p = beta*p + z; } // CALCULATES q = A*p AND dp = dot(q,p) real dp = multiply_dot(A, p, q); alpha = rho / dp; normr = 0; #ifdef USES_OPENMP #pragma omp parallel for reduction(+:normr) #endif for (idx j = 0 ; j < N ; ++j) { x[j] += alpha * p[j]; // x + alpha(0) * p; r[j] -= alpha * q[j]; // r - alpha(0) * q; normr += r[j] * r[j]; } normr = sqrt(normr); resid = normr / normb; if (resid <= IterativeSolvers::toler) { IterativeSolvers::toler = resid; IterativeSolvers::maxIter = i; return true; } rho_1 = rho; } IterativeSolvers::toler = resid; return false; }
/** Computes the area of triangle between vectors P1,P2,P3, * by computing the crossproduct P1P2 x P1P3 and taking the half of its norm */ inline double area_triangle(double *P1, double *P2, double *P3) { double area; double u[3],v[3],normal[3], n; //auxiliary variables u[0] = P2[0] - P1[0]; // u = P1P2 u[1] = P2[1] - P1[1]; u[2] = P2[2] - P1[2]; v[0] = P3[0] - P1[0]; // v = P1P3 v[1] = P3[1] - P1[1]; v[2] = P3[2] - P1[2]; vector_product(u,v,normal); n=normr(normal); area = 0.5*n; return area; }
inline void calc_volume(double *volume, int molType){ //first-fold-then-the-same approach double partVol=0.,A,norm[3],dn,hz; /** loop over particles */ int c, np, i ,j; Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; int img[3]; Bonded_ia_parameters *iaparams; int type_num, n_partners, id; BondedInteraction type; char *errtxt; //int test=0; //printf("rank%d, molType2: %d\n", rank,molType); /* Loop local cells */ for (c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; p = cell->part; np = cell->n; /* Loop cell particles */ for(i=0; i < np; i++) { j = 0; p1 = &p[i]; //printf("rank%d, i=%d neigh=%d\n", rank, i, p1->bl.n); while(j<p1->bl.n){ /* bond type */ type_num = p1->bl.e[j++]; //bond_number iaparams = &bonded_ia_params[type_num]; type = iaparams->type; //type of interaction 14...volume_force n_partners = iaparams->num; //bonded_neigbours id=p1->p.mol_id; //mol_id of blood cell if(type == BONDED_IA_VOLUME_FORCE && id == molType){ // BONDED_IA_VOLUME_FORCE with correct molType !!!!!!!!!!!!! needs area force local !!!!!!!!!!!!!!!!!! p2 = local_particles[p1->bl.e[j++]]; if (!p2) { printf("broken: particles sum %d, id %d, partn %d, bond %d\n", np,id,n_partners,type_num); errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{volume calc 078 bond broken between particles %d and %d (particles not stored on the same node - volume_force1)} ", p1->p.identity, p1->bl.e[j-1]); return; } /* fetch particle 3 */ p3 = local_particles[p1->bl.e[j++]]; if (!p3) { errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{volume calc 079 bond broken between particles %d, %d and %d (particles not stored on the same node); n %d max %d} ", p1->p.identity, p1->bl.e[j-2], p1->bl.e[j-1],p1->bl.n,p1->bl.max); return; } memcpy(p11, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(p11, img); memcpy(p22, p2->r.p, 3*sizeof(double)); memcpy(img, p2->l.i, 3*sizeof(int)); fold_position(p22, img); memcpy(p33, p3->r.p, 3*sizeof(double)); memcpy(img, p3->l.i, 3*sizeof(int)); fold_position(p33, img); get_n_triangle(p11,p22,p33,norm); dn=normr(norm); A=area_triangle(p11,p22,p33); hz=1.0/3.0 *(p11[2]+p22[2]+p33[2]); partVol += A * -1*norm[2]/dn * hz; } else{ j+=n_partners; } } } } MPI_Allreduce(&partVol, volume, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); }
inline void add_volume_force(double volume, int molType){ //first-fold-then-the-same approach double A,norm[3],dn; //partVol=0. double vv, force[3]; int k; int img[3]; /** loop over particles */ int c, np, i ,j; Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; Bonded_ia_parameters *iaparams; int type_num, n_partners, id; BondedInteraction type; char *errtxt; int test=0; /* Loop local cells */ for (c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; p = cell->part; np = cell->n; /* Loop cell particles */ for(i=0; i < np; i++) { j = 0; p1=&p[i]; //printf("i=%d neigh=%d\n", i, p1->bl.n); while(j<p1->bl.n){ /* bond type */ type_num = p1->bl.e[j++]; iaparams = &bonded_ia_params[type_num]; type = iaparams->type; n_partners = iaparams->num; id=p1->p.mol_id; if(type == BONDED_IA_VOLUME_FORCE && id == molType){ // BONDED_IA_VOLUME_FORCE with correct molType test++; /* fetch particle 2 */ p2 = local_particles[p1->bl.e[j++]]; if (!p2) { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{volume add 078 bond broken between particles %d and %d (particles not stored on the same node - volume_force2)} ", p1->p.identity, p1->bl.e[j-1]); return; } /* fetch particle 3 */ p3 = local_particles[p1->bl.e[j++]]; if (!p3) { errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{volume add 079 bond broken between particles %d, %d and %d (particles not stored on the same node); n %d max %d} ", p1->p.identity, p1->bl.e[j-2], p1->bl.e[j-1],p1->bl.n,p1->bl.max); return; } memcpy(p11, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); fold_position(p11, img); memcpy(p22, p2->r.p, 3*sizeof(double)); memcpy(img, p2->l.i, 3*sizeof(int)); fold_position(p22, img); memcpy(p33, p3->r.p, 3*sizeof(double)); memcpy(img, p3->l.i, 3*sizeof(int)); fold_position(p33, img); get_n_triangle(p11,p22,p33,norm); dn=normr(norm); A=area_triangle(p11,p22,p33); { } vv=(volume - iaparams->p.volume_force.V0)/iaparams->p.volume_force.V0; for(k=0;k<3;k++) { force[k]=iaparams->p.volume_force.kv * vv * A * norm[k]/dn * 1.0 / 3.0; //printf("%e ",force[k]); p1->f.f[k] += force[k]; p2->f.f[k] += force[k]; p3->f.f[k] += force[k]; } } else{ j+=n_partners; } } } } }
bool steepest_descent_step(void) { Cell *cell; Particle *p; int c, i, j, np; // Maximal force encountered on node double f_max = -std::numeric_limits<double>::max(); // and globally double f_max_global; // Square of force,torque on particle double f,t; // Positional increments double dp, dp2, dp2_max = -std::numeric_limits<double>::max(); // Iteration over all local particles for (c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; p = cell->part; np = cell->n; for(i = 0; i < np; i++) { f = 0.0; t = 0.0; dp2 = 0.0; #ifdef EXTERNAL_FORCES // Skip, if coordinate is fixed if (!(p[i].p.ext_flag & COORD_FIXED(j))) #endif // For all Cartesian coordinates for(j=0; j < 3; j++){ #ifdef VIRTUAL_SITES // Skip positional increments of virtual particles if (!ifParticleIsVirtual(&p[i])) #endif { // Square of force on particle f += SQR(p[i].f.f[j]); // Positional increment dp = params->gamma * p[i].f.f[j]; if(fabs(dp) > params->max_displacement) // Crop to maximum allowed by user dp = sgn<double>(dp)*params->max_displacement; dp2 += SQR(dp); // Move particle p[i].r.p[j] += dp; MINIMIZE_ENERGY_TRACE(printf("part %d dim %d dp %e gamma*f %e\n", i, j, dp, params->gamma * p[i].f.f[j])); } } #ifdef ROTATION // Rotational increment double dq[3]; // Vector parallel to torque for (int j=0;j<3;j++){ dq[j]=0; // Square of torque t += SQR(p[i].f.torque[j]); // Rotational increment dq[j] = params->gamma * p[i].f.torque[j]; } // Normalize rotation axis and compute amount of rotation double l=normr(dq); if (l>0.0) { for (j=0;j<3;j++) dq[j]/=l; if(fabs(l) > params->max_displacement) // Crop to maximum allowed by user l=sgn(l)*params->max_displacement; // printf("dq: %g %g %g, l=%g\n",dq[0],dq[1],dq[2],l); // Rotate the particle around axis dq by amount l rotate_particle(&(p[i]),dq,l); } #endif // Note maximum force/torque encountered f_max = std::max(f_max, f); f_max = std::max(f_max, t); dp2_max = std::max(dp2_max, dp2); resort_particles = 1; } } MINIMIZE_ENERGY_TRACE(printf("f_max %e resort_particles %d\n", f_max, resort_particles)); announce_resort_particles(); // Synchronize maximum force/torque encountered MPI_Allreduce(&f_max, &f_max_global, 1, MPI_DOUBLE, MPI_MAX, comm_cart); // Return true, if the maximum force/torque encountered is below the user limit. return (sqrt(f_max_global) < params->f_max); }
inline void calc_volume(double *volume, int molType){ //first-fold-then-the-same approach double partVol=0.,A,norm[3],dn,hz; /** loop over particles */ int c, np, i ,j; Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; int img[3]; double AA[3],BB[3]; Bonded_ia_parameters *iaparams; int type_num, n_partners, id; BondedInteraction type; //int test=0; //printf("rank%d, molType2: %d\n", rank,molType); /* Loop local cells */ for (c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; p = cell->part; np = cell->n; /* Loop cell particles */ for(i=0; i < np; i++) { j = 0; p1 = &p[i]; //printf("rank%d, i=%d neigh=%d\n", rank, i, p1->bl.n); while(j<p1->bl.n){ /* bond type */ type_num = p1->bl.e[j++]; //bond_number iaparams = &bonded_ia_params[type_num]; type = iaparams->type; //type of interaction 14...volume_force n_partners = iaparams->num; //bonded_neigbours id=p1->p.mol_id; //mol_id of blood cell if(type == BONDED_IA_VOLUME_FORCE && id == molType){ // BONDED_IA_VOLUME_FORCE with correct molType !!!!!!!!!!!!! needs area force local !!!!!!!!!!!!!!!!!! p2 = local_particles[p1->bl.e[j++]]; if (!p2) { printf("broken: particles sum %d, id %d, partn %d, bond %d\n", np,id,n_partners,type_num); ostringstream msg; msg <<"volume calc: bond broken between particles " << p1->p.identity << " and " << p1->bl.e[j-1] << " (particles not stored on the same node - volume_force1)"; runtimeError(msg); return; } /* fetch particle 3 */ p3 = local_particles[p1->bl.e[j++]]; if (!p3) { ostringstream msg; msg <<"volume calc: bond broken between particles " << p1->p.identity << ", " << p1->bl.e[j-2] << " and " << p1->bl.e[j-1] << " (particles not stored on the same node); n " << p1->bl.n << " max " << p1->bl.max; runtimeError(msg); return; } // particles fetched #ifdef GHOST_FLAG // first find out which particle out of p1, p2 (possibly p3, p4) is not a ghost particle. In almost all cases it is p1, however, it might be other one. we call this particle reference particle. if (p1->l.ghost != 1) { //unfold non-ghost particle using image, because for physical particles, the structure p->l.i is correctly set memmove(p11, p1->r.p, 3*sizeof(double)); memmove(img, p1->l.i, 3*sizeof(int)); unfold_position(p11,img); // other coordinates are obtained from its relative positions to the reference particle get_mi_vector(AA, p2->r.p, p11); get_mi_vector(BB, p3->r.p, p11); for (int i=0; i < 3; i++) { p22[i] = p11[i] + AA[i]; p33[i] = p11[i] + BB[i]; } } else { // in case the first particle is a ghost particle if (p2->l.ghost != 1) { memmove(p22, p2->r.p, 3*sizeof(double)); memmove(img, p2->l.i, 3*sizeof(int)); unfold_position(p22,img); get_mi_vector(AA, p1->r.p, p22); get_mi_vector(BB, p3->r.p, p22); for (int i=0; i < 3; i++) { p11[i] = p22[i] + AA[i]; p33[i] = p22[i] + BB[i]; } } else { // in case the first and the second particle are ghost particles if (p3->l.ghost != 1) { memmove(p33, p3->r.p, 3*sizeof(double)); memmove(img, p3->l.i, 3*sizeof(int)); unfold_position(p33,img); get_mi_vector(AA, p1->r.p, p33); get_mi_vector(BB, p2->r.p, p33); for (int i=0; i < 3; i++) { p11[i] = p33[i] + AA[i]; p22[i] = p33[i] + BB[i]; } } else { printf("Something wrong in area_force_local.hpp: All particles in a bond are ghost particles, impossible to unfold the positions..."); return; } } } #endif #ifndef GHOST_FLAG // if ghost flag was not defined we have no other option than to assume the first particle is a physical one. memmove(p11, p1->r.p, 3*sizeof(double)); memmove(img, p1->l.i, 3*sizeof(int)); unfold_position(p11,img); // other coordinates are obtained from its relative positions to the reference particle get_mi_vector(AA, p2->r.p, p11); get_mi_vector(BB, p3->r.p, p11); for (int i=0; i < 3; i++) { p22[i] = p11[i] + AA[i]; p33[i] = p11[i] + BB[i]; } #endif get_n_triangle(p11,p22,p33,norm); dn=normr(norm); A=area_triangle(p11,p22,p33); hz=1.0/3.0 *(p11[2]+p22[2]+p33[2]); partVol += A * -1*norm[2]/dn * hz; } else{ j+=n_partners; } } } } MPI_Allreduce(&partVol, volume, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); }
inline void add_volume_force(double volume, int molType){ //first-fold-then-the-same approach double A,norm[3],dn; //partVol=0. double vv, force[3]; int k; int img[3]; /** loop over particles */ int c, np, i ,j; Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; Bonded_ia_parameters *iaparams; int type_num, n_partners, id; BondedInteraction type; double AA[3],BB[3]; int test=0; /* Loop local cells */ for (c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; p = cell->part; np = cell->n; /* Loop cell particles */ for(i=0; i < np; i++) { j = 0; p1=&p[i]; //printf("i=%d neigh=%d\n", i, p1->bl.n); while(j<p1->bl.n){ /* bond type */ type_num = p1->bl.e[j++]; iaparams = &bonded_ia_params[type_num]; type = iaparams->type; n_partners = iaparams->num; id=p1->p.mol_id; if(type == BONDED_IA_VOLUME_FORCE && id == molType){ // BONDED_IA_VOLUME_FORCE with correct molType test++; /* fetch particle 2 */ p2 = local_particles[p1->bl.e[j++]]; if (!p2) { ostringstream msg; msg <<"volume add: bond broken between particles " << p1->p.identity << " and " << p1->bl.e[j-1] << " (particles not stored on the same node - volume_force2)"; runtimeError(msg); return; } /* fetch particle 3 */ p3 = local_particles[p1->bl.e[j++]]; if (!p3) { ostringstream msg; msg <<"volume calc: bond broken between particles " << p1->p.identity << ", " << p1->bl.e[j-2] << " and " << p1->bl.e[j-1] << " (particles not stored on the same node); n " << p1->bl.n << " max " << p1->bl.max; runtimeError(msg); return; } // particles fetched #ifdef GHOST_FLAG // first find out which particle out of p1, p2 (possibly p3, p4) is not a ghost particle. In almost all cases it is p1, however, it might be other one. we call this particle reference particle. if (p1->l.ghost != 1) { //unfold non-ghost particle using image, because for physical particles, the structure p->l.i is correctly set memmove(p11, p1->r.p, 3*sizeof(double)); memmove(img, p1->l.i, 3*sizeof(int)); unfold_position(p11,img); // other coordinates are obtained from its relative positions to the reference particle get_mi_vector(AA, p2->r.p, p11); get_mi_vector(BB, p3->r.p, p11); for (int i=0; i < 3; i++) { p22[i] = p11[i] + AA[i]; p33[i] = p11[i] + BB[i]; } } else { // in case the first particle is a ghost particle if (p2->l.ghost != 1) { memmove(p22, p2->r.p, 3*sizeof(double)); memmove(img, p2->l.i, 3*sizeof(int)); unfold_position(p22,img); get_mi_vector(AA, p1->r.p, p22); get_mi_vector(BB, p3->r.p, p22); for (int i=0; i < 3; i++) { p11[i] = p22[i] + AA[i]; p33[i] = p22[i] + BB[i]; } } else { // in case the first and the second particle are ghost particles if (p3->l.ghost != 1) { memmove(p33, p3->r.p, 3*sizeof(double)); memmove(img, p3->l.i, 3*sizeof(int)); unfold_position(p33,img); get_mi_vector(AA, p1->r.p, p33); get_mi_vector(BB, p2->r.p, p33); for (int i=0; i < 3; i++) { p11[i] = p33[i] + AA[i]; p22[i] = p33[i] + BB[i]; } } else { printf("Something wrong in area_force_local.hpp: All particles in a bond are ghost particles, impossible to unfold the positions..."); return; } } } #endif #ifndef GHOST_FLAG // if ghost flag was not defined we have no other option than to assume the first particle is a physical one. memmove(p11, p1->r.p, 3*sizeof(double)); memmove(img, p1->l.i, 3*sizeof(int)); unfold_position(p11,img); // other coordinates are obtained from its relative positions to the reference particle get_mi_vector(AA, p2->r.p, p11); get_mi_vector(BB, p3->r.p, p11); for (int i=0; i < 3; i++) { p22[i] = p11[i] + AA[i]; p33[i] = p11[i] + BB[i]; } #endif get_n_triangle(p11,p22,p33,norm); dn=normr(norm); A=area_triangle(p11,p22,p33); { } vv=(volume - iaparams->p.volume_force.V0)/iaparams->p.volume_force.V0; for(k=0;k<3;k++) { force[k]=iaparams->p.volume_force.kv * vv * A * norm[k]/dn * 1.0 / 3.0; //printf("%e ",force[k]); p1->f.f[k] += force[k]; p2->f.f[k] += force[k]; p3->f.f[k] += force[k]; } } else{ j+=n_partners; } } } } }