/** calculate buck_capradius from force_cap */ void calc_buck_cap_radii() { /* do not compute cap radii if force capping is individual */ if( force_cap != -1.0 ) { int i,j,cnt=0; IA_parameters *params = NULL; double force=0.0, frac2, frac6, frac8; double r0,r1 = 0.0,diff,exp_term,C_R,D_R; for(i=0; i<n_particle_types; i++) { for(j=0; j<n_particle_types; j++) { params = get_ia_param(i,j); if(force_cap>0.0 ) { force = -params->BUCK_F2; if (force_cap<force) { /* Solving numerically using Newton Raphson Technique */ force = 0.0; cnt = 0; r1 = (params->BUCK_cut+params->BUCK_discont)/2.0; //First guess value r0 = 0.0 ; while(fabs(r1 - r0)>1.0e-10) { r0 = r1; exp_term = params->BUCK_A*params->BUCK_B*exp(-params->BUCK_B*r0); frac2 = SQR(r0); frac6 = frac2*frac2*frac2; frac8 = frac6*frac2; C_R = 6.0*params->BUCK_C/frac8; D_R = 4.0*params->BUCK_D/frac6; diff = (exp_term - C_R*r0 - D_R*r0 - force_cap)/(-params->BUCK_B*exp_term + 7.0*C_R + 5.0*D_R); r1 = r0 - diff; if(r1>params->BUCK_discont) r1=0.5*(params->BUCK_discont+r0); cnt++; if(cnt>500) { fprintf(stderr,"%d: [email protected]: Failed to converge while determining Buckingham cap radius!!",this_node); fprintf(stderr,"%d: tolerance = %f",this_node, diff); errexit(); } } frac2 = SQR(r1); frac6 = frac2*frac2*frac2; force = params->BUCK_A*params->BUCK_B*exp(-params->BUCK_B*r1) - 6.0*params->BUCK_C/(r1*frac6) - 4.0*params->BUCK_D*r1/(frac6); params->BUCK_capradius = r1; } else params->BUCK_capradius = params->BUCK_discont; } else params->BUCK_capradius = 0.0; FORCE_TRACE(fprintf(stderr,"%d: Ptypes %d-%d have cap_radius %f and cap_force %f (iterations: %d)\n", this_node,i,j,r1,force,cnt)); } } BUCK_TRACE(fprintf(stderr,"%d: BUCK: Buckingham force cap imposed %f, Calculated force %f and Cap radius %f after %d iterations\n",this_node,force_cap,force,params->BUCK_capradius,cnt); );
/** calculate ljcos2_capradius from force_cap */ void calc_ljcos2_cap_radii() { /* do not compute cap radii if force capping is "individual" */ if( force_cap != -1.0){ int i,j,cnt=0; IA_parameters *params; double force=0.0, rad=0.0, step, frac2, frac6; for(i=0; i<n_particle_types; i++) { for(j=0; j<n_particle_types; j++) { params = get_ia_param(i,j); if(force_cap > 0.0 && params->LJCOS2_eps > 0.0) { /* I think we have to solve this numerically... and very crude as well */ cnt=0; rad = params->LJCOS2_sig; step = -0.1 * params->LJCOS2_sig; force=0.0; while(step != 0) { frac2 = SQR(params->LJCOS2_sig/rad); frac6 = frac2*frac2*frac2; if (rad < params->LJCOS2_rchange) { force = 48.0 * params->LJCOS2_eps * frac6*(frac6 - 0.5)/rad; } else { force = 0; } if((step < 0 && force_cap < force) || (step > 0 && force_cap > force)) { step = - (step/2.0); } if(fabs(force-force_cap) < 1.0e-6) step=0; rad += step; cnt++; } params->LJCOS2_capradius = rad; } else { params->LJCOS2_capradius = 0.0; } FORCE_TRACE(fprintf(stderr,"%d: Ptypes %d-%d have cap_radius %f and cap_force %f (iterations: %d)\n", this_node,i,j,rad,force,cnt)); } } } }
/** calculate lj_capradius from force_cap */ void calc_ljgen_cap_radii() { /* do not compute cap radii if force capping is "individual" */ if( force_cap != -1.0){ int i,j,cnt=0; IA_parameters *params; double force=0.0, rad=0.0, step, frac; for(i=0; i<n_particle_types; i++) { for(j=0; j<n_particle_types; j++) { params = get_ia_param(i,j); if(force_cap > 0.0 && params->LJGEN_eps > 0.0) { /* I think we have to solve this numerically... and very crude as well */ cnt=0; rad = params->LJGEN_sig; step = -0.1 * params->LJGEN_sig; force=0.0; while(step != 0) { frac = params->LJGEN_sig/rad; force = params->LJGEN_eps #ifdef LJGEN_SOFTCORE * params->LJGEN_lambda #endif * (params->LJGEN_b1 * params->LJGEN_a1 * pow(frac, params->LJGEN_a1) - params->LJGEN_b2 * params->LJGEN_a2 * pow(frac, params->LJGEN_a2))/rad; if((step < 0 && force_cap < force) || (step > 0 && force_cap > force)) { step = - (step/2.0); } if(fabs(force-force_cap) < 1.0e-6) step=0; rad += step; cnt++; } params->LJGEN_capradius = rad; } else { params->LJGEN_capradius = 0.0; } FORCE_TRACE(fprintf(stderr,"%d: Ptypes %d-%d have cap_radius %f and cap_force %f (iterations: %d)\n", this_node,i,j,rad,force,cnt)); } } } }
void calc_morse_cap_radii() { /* do not compute cap radii if force capping is "individual" */ if( force_cap != -1.0){ int i,j,cnt=0; IA_parameters *params; double force=0.0, rad=0.0, step, add1, add2; for(i=0; i<n_particle_types; i++) { for(j=0; j<n_particle_types; j++) { params = get_ia_param(i,j); if(force_cap > 0.0 && params->MORSE_eps > 0.0) { /* I think we have to solve this numerically... and very crude as well */ cnt=0; rad = params->MORSE_rmin - 0.69314719 / params->MORSE_alpha; step = -0.1 * rad; force=0.0; while(step != 0) { add1 = exp(-2.0 * params->MORSE_alpha * (rad - params->MORSE_rmin)); add2 = exp( -params->MORSE_alpha * (rad - params->MORSE_rmin)); force = -params->MORSE_eps * 2.0 * params->MORSE_alpha * (add2 - add1) / rad; if((step < 0 && force_cap < force) || (step > 0 && force_cap > force)) { step = - (step/2.0); } if(fabs(force-force_cap) < 1.0e-6) step=0; rad += step; cnt++; } params->MORSE_capradius = rad; } else { params->MORSE_capradius = 0.0; } FORCE_TRACE(fprintf(stderr,"%d: Ptypes %d-%d have cap_radius %f and cap_force %f (iterations: %d)\n", this_node,i,j,rad,force,cnt)); } } } }
/* This routine does not take the optional 2nd environment into account. */ void calc_ljangle_cap_radii() { if( force_cap != -1.0){ int i,j,cnt=0; IA_parameters *params; double force=0.0, rad=0.0, step, frac2, frac10; for(i=0; i<n_particle_types; i++) { for(j=0; j<n_particle_types; j++) { params = get_ia_param(i,j); if(force_cap > 0.0 && params->LJANGLE_eps > 0.0) { /* I think we have to solve this numerically... and very crude as well */ cnt=0; rad = params->LJANGLE_sig; step = -0.1 * params->LJANGLE_sig; force=0.0; while(step != 0) { frac2 = SQR(params->LJANGLE_sig/rad); frac10 = frac2*frac2*frac2*frac2*frac2; force = 60.0 * params->LJANGLE_eps * frac10*(frac2 - 1.0) / rad; if((step < 0 && force_cap < force) || (step > 0 && force_cap > force)) { step = - (step/2.0); } if(fabs(force-force_cap) < 1.0e-6) step=0; rad += step; cnt++; } params->LJANGLE_capradius = rad; } else { params->LJANGLE_capradius = 0.0; } FORCE_TRACE(fprintf(stderr,"%d: LJANGLE Ptypes %d-%d have cap_radius %f and cap_force %f (iterations: %d)\n", this_node,i,j,rad,force,cnt)); } } } }
/** 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 } }
void calc_long_range_forces() { #ifdef ELECTROSTATICS /* calculate k-space part of electrostatic interaction. */ switch (coulomb.method) { #ifdef P3M case COULOMB_ELC_P3M: if (elc_params.dielectric_contrast_on) { ELC_P3M_modify_p3m_sums_both(); ELC_p3m_charge_assign_both(); ELC_P3M_self_forces(); } else p3m_charge_assign(); p3m_calc_kspace_forces(1,0); if (elc_params.dielectric_contrast_on) ELC_P3M_restore_p3m_sums(); ELC_add_force(); break; #endif #ifdef CUDA case COULOMB_P3M_GPU: if (this_node == 0) { FORCE_TRACE(printf("Computing GPU P3M forces.\n")); p3m_gpu_add_farfield_force(); } /* there is no NPT handling here as long as we cannot compute energies. This is checked in integrator_npt_sanity_checks() when integration starts. */ break; #endif #ifdef P3M case COULOMB_P3M: FORCE_TRACE(printf("%d: Computing P3M forces.\n", this_node)); p3m_charge_assign(); #ifdef NPT if (integ_switch == INTEG_METHOD_NPT_ISO) nptiso.p_vir[0] += p3m_calc_kspace_forces(1,1); else #endif p3m_calc_kspace_forces(1, 0); break; #endif case COULOMB_MAGGS: maggs_calc_forces(); break; case COULOMB_MMM2D: MMM2D_add_far_force(); MMM2D_dielectric_layers_force_contribution(); break; #ifdef SCAFACOS case COULOMB_SCAFACOS: Electrostatics::Scafacos::add_long_range_force(); break; #endif default: break; } /* If enabled, calculate electrostatics contribution from electrokinetics species. */ #ifdef EK_ELECTROSTATIC_COUPLING ek_calculate_electrostatic_coupling(); #endif #endif /*ifdef ELECTROSTATICS */ #ifdef DIPOLES /* calculate k-space part of the magnetostatic interaction. */ switch (coulomb.Dmethod) { #ifdef DP3M case DIPOLAR_MDLC_P3M: add_mdlc_force_corrections(); //fall through case DIPOLAR_P3M: dp3m_dipole_assign(); #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO) { nptiso.p_vir[0] += dp3m_calc_kspace_forces(1,1); fprintf(stderr,"dipolar_P3M at this moment is added to p_vir[0]\n"); } else #endif dp3m_calc_kspace_forces(1,0); break; #endif case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA: dawaanr_calculations(1,0); break; case DIPOLAR_MDLC_DS: add_mdlc_force_corrections(); //fall through case DIPOLAR_DS: magnetic_dipolar_direct_sum_calculations(1,0); break; case DIPOLAR_DS_GPU: // Do nothing. It's an actor break; case DIPOLAR_NONE: break; default: runtimeErrorMsg() <<"unknown dipolar method"; break; } #endif /*ifdef DIPOLES */ }