/** Calculate non bonded energies between a pair of particles. @param p1 pointer to particle 1. @param p2 pointer to particle 2. @param d vector between p1 and p2. @param dist distance between p1 and p2. @param dist2 distance squared between p1 and p2. */ inline void add_non_bonded_pair_virials(Particle *p1, Particle *p2, double d[3], double dist, double dist2) { int p1molid, p2molid, k, l; double force[3] = {0, 0, 0}; calc_non_bonded_pair_force(p1, p2,d, dist, dist2, force); *obsstat_nonbonded(&virials, p1->p.type, p2->p.type) += d[0]*force[0] + d[1]*force[1] + d[2]*force[2]; /* stress tensor part */ for(k=0; k<3; k++) for(l=0; l<3; l++) obsstat_nonbonded(&p_tensor, p1->p.type, p2->p.type)[k*3 + l] += force[k]*d[l]; p1molid = p1->p.mol_id; p2molid = p2->p.mol_id; if ( p1molid == p2molid ) { *obsstat_nonbonded_intra(&virials_non_bonded, p1->p.type, p2->p.type) += d[0]*force[0] + d[1]*force[1] + d[2]*force[2]; for(k=0; k<3; k++) for(l=0; l<3; l++) obsstat_nonbonded_intra(&p_tensor_non_bonded, p1->p.type, p2->p.type)[k*3 + l] += force[k]*d[l]; } if ( p1molid != p2molid ) { *obsstat_nonbonded_inter(&virials_non_bonded, p1->p.type, p2->p.type) += d[0]*force[0] + d[1]*force[1] + d[2]*force[2]; for(k=0; k<3; k++) for(l=0; l<3; l++) obsstat_nonbonded_inter(&p_tensor_non_bonded, p1->p.type, p2->p.type)[k*3 + l] += force[k]*d[l]; } #ifdef ELECTROSTATICS /* real space coulomb */ if (coulomb.method != COULOMB_NONE) { switch (coulomb.method) { #ifdef P3M case COULOMB_P3M_GPU: case COULOMB_P3M: force[0] = 0.0; force[1] = 0.0; force[2] = 0.0; p3m_add_pair_force(p1->p.q*p2->p.q, d, dist2, dist, force); virials.coulomb[0] += p3m_pair_energy(p1->p.q*p2->p.q,d,dist2,dist); for (k = 0; k<3; k++) for (l = 0; l<3; l++) p_tensor.coulomb[k*3 + l] += force[k]*d[l]; break; #endif /* short range potentials, where we use the virial */ /***************************************************/ case COULOMB_DH: { double force[3] = {0, 0, 0}; add_dh_coulomb_pair_force(p1,p2,d,dist, force); for(k=0; k<3; k++) for(l=0; l<3; l++) p_tensor.coulomb[k*3 + l] += force[k]*d[l]; virials.coulomb[0] += force[0]*d[0] + force[1]*d[1] + force[2]*d[2]; break; } case COULOMB_RF: { double force[3] = {0, 0, 0}; add_rf_coulomb_pair_force(p1,p2,d,dist, force); for(k=0; k<3; k++) for(l=0; l<3; l++) p_tensor.coulomb[k*3 + l] += force[k]*d[l]; virials.coulomb[0] += force[0]*d[0] + force[1]*d[1] + force[2]*d[2]; break; } case COULOMB_INTER_RF: // this is done together with the other short range interactions break; default: fprintf(stderr,"calculating pressure for electrostatics method that doesn't have it implemented\n"); break; } } #endif /*ifdef ELECTROSTATICS */ #ifdef DIPOLES /* real space magnetic dipole-dipole */ if (coulomb.Dmethod != DIPOLAR_NONE) { fprintf(stderr,"calculating pressure for magnetostatics which doesn't have it implemented\n"); } #endif /*ifdef DIPOLES */ }
/** Calculate non bonded forces between a pair of particles. @param p1 pointer to particle 1. @param p2 pointer to particle 2. @param d vector between p1 and p2. @param dist distance between p1 and p2. @param dist2 distance squared between p1 and p2. */ inline void add_non_bonded_pair_force(Particle *p1, Particle *p2, double d[3], double dist, double dist2) { IA_parameters *ia_params = get_ia_param(p1->p.type,p2->p.type); double force[3] = { 0., 0., 0. }; double torque1[3] = { 0., 0., 0. }; double torque2[3] = { 0., 0., 0. }; int j; /***********************************************/ /* bond creation and breaking */ /***********************************************/ #ifdef COLLISION_DETECTION if (collision_params.mode > 0) detect_collision(p1,p2); #endif /*affinity potential*/ #ifdef AFFINITY add_affinity_pair_force(p1,p2,ia_params,d,dist,force); #endif FORCE_TRACE(fprintf(stderr, "%d: interaction %d<->%d dist %f\n", this_node, p1->p.identity, p2->p.identity, dist)); /***********************************************/ /* thermostat */ /***********************************************/ #ifdef DPD /* DPD thermostat forces */ if ( thermo_switch & THERMO_DPD ) add_dpd_thermo_pair_force(p1,p2,d,dist,dist2); #endif /** The inter dpd force should not be part of the virial #ifdef INTER_DPD add_inter_dpd_pair_force(p1,p2,ia_params,d,dist,dist2); #endif /***********************************************/ /* non bonded pair potentials */ /***********************************************/ calc_non_bonded_pair_force(p1,p2,ia_params,d,dist,dist2,force,torque1,torque2); /***********************************************/ /* short range electrostatics */ /***********************************************/ #ifdef ELECTROSTATICS if (coulomb.method == COULOMB_DH) add_dh_coulomb_pair_force(p1,p2,d,dist,force); if (coulomb.method == COULOMB_RF) add_rf_coulomb_pair_force(p1,p2,d,dist,force); #endif /*********************************************************************/ /* everything before this contributes to the virial pressure in NpT, */ /* but nothing afterwards */ /*********************************************************************/ #ifdef NPT for (j = 0; j < 3; j++) if(integ_switch == INTEG_METHOD_NPT_ISO) nptiso.p_vir[j] += force[j] * d[j]; #endif /***********************************************/ /* semi-bonded multi-body potentials */ /***********************************************/ /* Directional LJ */ #ifdef LJ_ANGLE /* This is a multi-body forces that changes the forces of 6 particles */ add_ljangle_force(p1, p2, ia_params, d, dist); #endif /***********************************************/ /* long range electrostatics */ /***********************************************/ #ifdef ELECTROSTATICS /* real space coulomb */ double q1q2 = p1->p.q*p2->p.q; switch (coulomb.method) { #ifdef P3M case COULOMB_ELC_P3M: { if (q1q2) { p3m_add_pair_force(q1q2,d,dist2,dist,force); // forces from the virtual charges // they go directly onto the particles, since they are not pairwise forces if (elc_params.dielectric_contrast_on) ELC_P3M_dielectric_layers_force_contribution(p1, p2, p1->f.f, p2->f.f); } break; } case COULOMB_P3M_GPU: case COULOMB_P3M: { #ifdef NPT if (q1q2) { double eng = p3m_add_pair_force(q1q2,d,dist2,dist,force); if(integ_switch == INTEG_METHOD_NPT_ISO) nptiso.p_vir[0] += eng; } #else if (q1q2) p3m_add_pair_force(q1q2,d,dist2,dist,force); #endif break; } #endif case COULOMB_MMM1D: if (q1q2) add_mmm1d_coulomb_pair_force(q1q2,d,dist2,dist,force); break; case COULOMB_MMM2D: if (q1q2) add_mmm2d_coulomb_pair_force(q1q2,d,dist2,dist,force); break; #ifdef EWALD_GPU case COULOMB_EWALD_GPU: if (q1q2) add_ewald_gpu_coulomb_pair_force(p1,p2,d,dist,force); break; #endif default: break; } #endif /*ifdef ELECTROSTATICS */ /***********************************************/ /* long range magnetostatics */ /***********************************************/ #ifdef DIPOLES /* real space magnetic dipole-dipole */ switch (coulomb.Dmethod) { #ifdef DP3M case DIPOLAR_MDLC_P3M: //fall trough case DIPOLAR_P3M: { #ifdef NPT double eng = dp3m_add_pair_force(p1,p2,d,dist2,dist,force); if(integ_switch == INTEG_METHOD_NPT_ISO) nptiso.p_vir[0] += eng; #else dp3m_add_pair_force(p1,p2,d,dist2,dist,force); #endif break; } #endif /*ifdef DP3M */ default: break; } #endif /* ifdef DIPOLES */ /***********************************************/ /* add total nonbonded forces to particle */ /***********************************************/ for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; p2->f.f[j] -= force[j]; #ifdef ROTATION p1->f.torque[j] += torque1[j]; p2->f.torque[j] += torque2[j]; #endif } }