inline void add_bonded_force(Particle *p1) { double dx[3] = { 0., 0., 0. }; double force[3] = { 0., 0., 0. }; double force2[3] = { 0., 0., 0. }; double force3[3] = { 0., 0., 0. }; #if defined(HYDROGEN_BOND) || defined(TWIST_STACK) || defined(OIF_LOCAL_FORCES) double force4[3] = { 0., 0., 0. }; #endif #ifdef TWIST_STACK double force5[3] = { 0., 0., 0. }; double force6[3] = { 0., 0., 0. }; double force7[3] = { 0., 0., 0. }; double force8[3] = { 0., 0., 0. }; Particle *p5 = NULL,*p6 = NULL,*p7 = NULL,*p8 = NULL; #endif #ifdef ROTATION double torque1[3] = { 0., 0., 0. }; double torque2[3] = { 0., 0., 0. }; #endif Particle *p2 = NULL, *p3 = NULL, *p4 = NULL; Bonded_ia_parameters *iaparams; int i, j, type_num, type, n_partners, bond_broken; i = 0; while (i<p1->bl.n) { type_num = p1->bl.e[i++]; iaparams = &bonded_ia_params[type_num]; type = iaparams->type; n_partners = iaparams->num; /* fetch particle 2, which is always needed */ p2 = local_particles[p1->bl.e[i++]]; if (!p2) { ostringstream msg; msg << "bond broken between particles " << p1->p.identity << " and " << p1->bl.e[i-1] << " (particles are not stored on the same node)"; runtimeError(msg); return; } /* fetch particle 3 eventually */ if (n_partners >= 2) { p3 = local_particles[p1->bl.e[i++]]; if (!p3) { ostringstream msg; msg << "bond broken between particles " << p1->p.identity << ", " << p1->bl.e[i-2] << " and " << p1->bl.e[i-1] << " (particles are not stored on the same node)"; runtimeError(msg); return; } } /* fetch particle 4 eventually */ if (n_partners >= 3) { p4 = local_particles[p1->bl.e[i++]]; if (!p4) { ostringstream msg; msg <<"bond broken between particles "<< p1->p.identity << ", " << p1->bl.e[i-3] << ", " << p1->bl.e[i-2] << " and " << p1->bl.e[i-1] << " (particles not stored on the same node)"; runtimeError(msg); return; } } #ifdef TWIST_STACK if(n_partners >= 7) { p5 = local_particles[p1->bl.e[i++]]; p6 = local_particles[p1->bl.e[i++]]; p7 = local_particles[p1->bl.e[i++]]; p8 = local_particles[p1->bl.e[i++]]; if(!p4 || !p5 || !p6 || !p7 || !p8) { ostringstream msg; msg << "bond broken between particles" << p1->p.identity << ", " << p1->bl.e[i-7] << ", " << p1->bl.e[i-6] << ", " << p1->bl.e[i-5] << ", " << p1->bl.e[i-4] << ", " << p1->bl.e[i-3] << ", " << p1->bl.e[i-2] << ", " << p1->bl.e[i-1] << " (particles not stored on the same node)"; return; } } #endif if (n_partners == 1) { /* because of the NPT pressure calculation for pair forces, we need the 1->2 distance vector here. For many body interactions this vector is not needed, and the pressure calculation not yet clear. */ get_mi_vector(dx, p1->r.p, p2->r.p); } switch (type) { case BONDED_IA_FENE: bond_broken = calc_fene_pair_force(p1, p2, iaparams, dx, force); break; #ifdef ROTATION case BONDED_IA_HARMONIC_DUMBBELL: bond_broken = calc_harmonic_dumbbell_pair_force(p1, p2, iaparams, dx, force); break; #endif case BONDED_IA_HARMONIC: bond_broken = calc_harmonic_pair_force(p1, p2, iaparams, dx, force); break; case BONDED_IA_QUARTIC: bond_broken = calc_quartic_pair_force(p1, p2, iaparams, dx, force); break; #ifdef ELECTROSTATICS case BONDED_IA_BONDED_COULOMB: bond_broken = calc_bonded_coulomb_pair_force(p1, p2, iaparams, dx, force); break; #endif #ifdef HYDROGEN_BOND case BONDED_IA_CG_DNA_BASEPAIR: bond_broken = calc_hydrogen_bond_force(p1, p2, p3, p4, iaparams, force, force2, force3, force4); break; #endif #ifdef TWIST_STACK case BONDED_IA_CG_DNA_STACKING: bond_broken = calc_twist_stack_force(p1, p2, p3, p4, p5, p6, p7, p8, iaparams, force, force2, force3, force4, force5, force6, force7, force8); break; #endif #ifdef MEMBRANE_COLLISION case BONDED_IA_OIF_OUT_DIRECTION: bond_broken = calc_out_direction(p1, p2, p3, p4, iaparams); break; #endif #ifdef OIF_GLOBAL_FORCES case BONDED_IA_OIF_GLOBAL_FORCES: bond_broken = 0; break; #endif #ifdef OIF_LOCAL_FORCES case BONDED_IA_OIF_LOCAL_FORCES: bond_broken = calc_oif_local(p1, p2, p3, p4, iaparams, force, force2, force3, force4); break; #endif // IMMERSED_BOUNDARY #ifdef IMMERSED_BOUNDARY /* case BONDED_IA_IBM_WALL_REPULSION: IBM_WallRepulsion_CalcForce(p1, iaparams); bond_broken = 0; // These may be added later on, but we set them to zero because the force has already been added in IBM_WallRepulsion_CalcForce force[0] = force2[0] = force3[0] = 0; force[1] = force2[1] = force3[1] = 0; force[2] = force2[2] = force3[2] = 0; break;*/ case BONDED_IA_IBM_TRIEL: bond_broken = IBM_Triel_CalcForce(p1, p2, p3, iaparams); // These may be added later on, but we set them to zero because the force has already been added in IBM_Triel_CalcForce force[0] = force2[0] = force3[0] = 0; force[1] = force2[1] = force3[1] = 0; force[2] = force2[2] = force3[2] = 0; break; case BONDED_IA_IBM_VOLUME_CONSERVATION: bond_broken = 0; // Don't do anything here. We calculate and add the global volume forces in IBM_VolumeConservation. They cannot be calculated on a per-bond basis force[0] = force2[0] = force3[0] = 0; force[1] = force2[1] = force3[1] = 0; force[2] = force2[2] = force3[2] = 0; break; case BONDED_IA_IBM_TRIBEND: { // First build neighbor list. This includes all nodes around the central node. const int numNeighbors = iaparams->num; Particle **neighbors = new Particle *[numNeighbors]; // Three are already there neighbors[0] = p2; neighbors[1] = p3; neighbors[2] = p4; // Get rest for (int j=3; j < numNeighbors; j++) neighbors[j] = local_particles[p1->bl.e[i++]]; IBM_Tribend_CalcForce(p1, numNeighbors, neighbors, *iaparams); bond_broken = 0; // Clean up delete []neighbors; // These may be added later on, but we set them to zero because the force has force[0] = force2[0] = force3[0] = 0; force[1] = force2[1] = force3[1] = 0; force[2] = force2[2] = force3[2] = 0; break; } #endif #ifdef LENNARD_JONES case BONDED_IA_SUBT_LJ: bond_broken = calc_subt_lj_pair_force(p1, p2, iaparams, dx, force); break; #endif #ifdef BOND_ANGLE_OLD /* the first case is not needed and should not be called */ case BONDED_IA_ANGLE_OLD: bond_broken = calc_angle_force(p1, p2, p3, iaparams, force, force2); break; #endif #ifdef BOND_ANGLE case BONDED_IA_ANGLE_HARMONIC: bond_broken = calc_angle_harmonic_force(p1, p2, p3, iaparams, force, force2); break; case BONDED_IA_ANGLE_COSINE: bond_broken = calc_angle_cosine_force(p1, p2, p3, iaparams, force, force2); break; case BONDED_IA_ANGLE_COSSQUARE: bond_broken = calc_angle_cossquare_force(p1, p2, p3, iaparams, force, force2); break; #endif #ifdef BOND_ANGLEDIST case BONDED_IA_ANGLEDIST: bond_broken = calc_angledist_force(p1, p2, p3, iaparams, force, force2); break; #endif #ifdef BOND_ENDANGLEDIST case BONDED_IA_ENDANGLEDIST: bond_broken = calc_endangledist_pair_force(p1, p2, iaparams, dx, force, force2); break; #endif case BONDED_IA_DIHEDRAL: bond_broken = calc_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; #ifdef BOND_CONSTRAINT case BONDED_IA_RIGID_BOND: //add_rigid_bond_pair_force(p1,p2, iaparams, force, force2); bond_broken = 0; force[0]=force[1]=force[2]=0.0; break; #endif #ifdef TABULATED case BONDED_IA_TABULATED: switch(iaparams->p.tab.type) { case TAB_BOND_LENGTH: bond_broken = calc_tab_bond_force(p1, p2, iaparams, dx, force); break; case TAB_BOND_ANGLE: bond_broken = calc_tab_angle_force(p1, p2, p3, iaparams, force, force2); break; case TAB_BOND_DIHEDRAL: bond_broken = calc_tab_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; default: ostringstream msg; msg << "add_bonded_force: tabulated bond type of atom "<< p1->p.identity << " unknown\n"; runtimeError(msg); return; } break; #endif #ifdef OVERLAPPED case BONDED_IA_OVERLAPPED: switch(iaparams->p.overlap.type) { case OVERLAP_BOND_LENGTH: bond_broken = calc_overlap_bond_force(p1, p2, iaparams, dx, force); break; case OVERLAP_BOND_ANGLE: bond_broken = calc_overlap_angle_force(p1, p2, p3, iaparams, force, force2); break; case OVERLAP_BOND_DIHEDRAL: bond_broken = calc_overlap_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; default: ostringstream msg; msg <<"add_bonded_force: overlapped bond type of atom "<< p1->p.identity << " unknown\n"; runtimeError(msg); return; } break; #endif #ifdef BOND_VIRTUAL case BONDED_IA_VIRTUAL_BOND: bond_broken = 0; force[0]=force[1]=force[2]=0.0; break; #endif default : ostringstream msg; msg <<"add_bonded_force: bond type of atom "<< p1->p.identity << " unknown\n"; runtimeError(msg); return; } switch (n_partners) { case 1: if (bond_broken) { ostringstream msg; msg <<"bond broken between particles " << p1->p.identity << " and " << p2->p.identity<<". Distance vector: "<<dx[0]<<" "<<dx[1]<<" "<<dx[2]; runtimeError(msg); continue; } for (j = 0; j < 3; j++) { switch (type) { #ifdef BOND_ENDANGLEDIST case BONDED_IA_ENDANGLEDIST: p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; break; #endif // BOND_ENDANGLEDIST default: 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 } #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO) nptiso.p_vir[j] += force[j] * dx[j]; #endif } break; case 2: if (bond_broken) { ostringstream msg; msg << "bond broken between particles "<< p1->p.identity << ", " << p2->p.identity << " and " << p3->p.identity; runtimeError(msg); continue; } for (j = 0; j < 3; j++) { switch (type) { #ifdef OIF_GLOBAL_FORCES case BONDED_IA_OIF_GLOBAL_FORCES: break; #endif default: p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; p3->f.f[j] -= (force[j] + force2[j]); } } break; case 3: if (bond_broken) { ostringstream msg; msg << "bond broken between particles "<< p1->p.identity << ", " << p2->p.identity << ", " << p3->p.identity << " and " << p4->p.identity; runtimeError(msg); continue; } switch (type) { case BONDED_IA_DIHEDRAL: for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; p3->f.f[j] += force3[j]; p4->f.f[j] -= force[j] + force2[j] + force3[j]; } break; #ifdef OIF_LOCAL_FORCES case BONDED_IA_OIF_LOCAL_FORCES: for (j = 0; j < 3; j++) { p1->f.f[j] += force2[j]; p2->f.f[j] += force[j]; p3->f.f[j] += force3[j]; p4->f.f[j] += force4[j]; } break; #endif #ifdef CG_DNA default: for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; p3->f.f[j] += force3[j]; p4->f.f[j] += force4[j]; } break; #endif } break; case 7: if (bond_broken) { ostringstream msg; msg << "bond broken between particles "<< p1->p.identity << ", " << p2->p.identity << ", " << p3->p.identity << " and " << p4->p.identity; runtimeError(msg); continue; } switch(type) { case BONDED_IA_CG_DNA_STACKING: #ifdef CG_DNA for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; p3->f.f[j] += force3[j]; p4->f.f[j] += force4[j]; p5->f.f[j] += force5[j]; p6->f.f[j] += force6[j]; p7->f.f[j] += force7[j]; p8->f.f[j] += force8[j]; } #endif break; } } } }
/** Calculate bonded forces for one particle. @param p1 particle for which to calculate forces */ inline void add_bonded_force(Particle *p1) { double dx[3] = { 0., 0., 0. }; double force[3] = { 0., 0., 0. }; double force2[3] = { 0., 0., 0. }; double force3[3] = { 0., 0., 0. }; #ifdef ROTATION double torque1[3] = { 0., 0., 0. }; double torque2[3] = { 0., 0., 0. }; #endif char *errtxt; Particle *p2, *p3 = NULL, *p4 = NULL; Bonded_ia_parameters *iaparams; int i, j, type_num, type, n_partners, bond_broken; i = 0; while(i<p1->bl.n) { type_num = p1->bl.e[i++]; iaparams = &bonded_ia_params[type_num]; type = iaparams->type; n_partners = iaparams->num; /* fetch particle 2, which is always needed */ p2 = local_particles[p1->bl.e[i++]]; if (!p2) { errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{078 bond broken between particles %d and %d (particles not stored on the same node)} ", p1->p.identity, p1->bl.e[i-1]); return; } /* fetch particle 3 eventually */ if (n_partners >= 2) { p3 = local_particles[p1->bl.e[i++]]; if (!p3) { errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{079 bond broken between particles %d, %d and %d (particles not stored on the same node)} ", p1->p.identity, p1->bl.e[i-2], p1->bl.e[i-1]); return; } } /* fetch particle 4 eventually */ if (n_partners >= 3) { p4 = local_particles[p1->bl.e[i++]]; if (!p4) { errtxt = runtime_error(128 + 4*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{080 bond broken between particles %d, %d, %d and %d (particles not stored on the same node)} ", p1->p.identity, p1->bl.e[i-3], p1->bl.e[i-2], p1->bl.e[i-1]); return; } } if (n_partners == 1) { /* because of the NPT pressure calculation for pair forces, we need the 1->2 distance vector here. For many body interactions this vector is not needed, and the pressure calculation not yet clear. */ get_mi_vector(dx, p1->r.p, p2->r.p); } switch (type) { case BONDED_IA_FENE: bond_broken = calc_fene_pair_force(p1, p2, iaparams, dx, force); break; case BONDED_IA_HARMONIC: bond_broken = calc_harmonic_pair_force(p1, p2, iaparams, dx, force); break; case BONDED_IA_STRETCHING_FORCE: bond_broken = calc_stretching_force_pair_force(p1, p2, iaparams, dx, force); break; case BONDED_IA_STRETCHLIN_FORCE: bond_broken = calc_stretchlin_force_pair_force(p1, p2, iaparams, dx, force); break; case BONDED_IA_AREA_FORCE_LOCAL: bond_broken = calc_area_force_local(p1, p2, p3, iaparams, force, force2, force3); break; #ifdef AREA_FORCE_GLOBAL case BONDED_IA_AREA_FORCE_GLOBAL: bond_broken = 0; break; #endif case BONDED_IA_BENDING_FORCE: bond_broken = calc_bending_force(p1, p2, p3, p4, iaparams, force, force2); break; #ifdef VOLUME_FORCE case BONDED_IA_VOLUME_FORCE: bond_broken = 0; break; #endif #ifdef LENNARD_JONES case BONDED_IA_SUBT_LJ: bond_broken = calc_subt_lj_pair_force(p1, p2, iaparams, dx, force); break; #endif #ifdef BOND_ANGLE_OLD /* the first case is not needed and should not be called */ case BONDED_IA_ANGLE_OLD: bond_broken = calc_angle_force(p1, p2, p3, iaparams, force, force2); break; #endif #ifdef BOND_ANGLE case BONDED_IA_ANGLE_HARMONIC: bond_broken = calc_angle_harmonic_force(p1, p2, p3, iaparams, force, force2); break; case BONDED_IA_ANGLE_COSINE: bond_broken = calc_angle_cosine_force(p1, p2, p3, iaparams, force, force2); break; case BONDED_IA_ANGLE_COSSQUARE: bond_broken = calc_angle_cossquare_force(p1, p2, p3, iaparams, force, force2); break; #endif #ifdef BOND_ANGLEDIST case BONDED_IA_ANGLEDIST: bond_broken = calc_angledist_force(p1, p2, p3, iaparams, force, force2); break; #endif #ifdef BOND_ENDANGLEDIST case BONDED_IA_ENDANGLEDIST: bond_broken = calc_endangledist_pair_force(p1, p2, iaparams, dx, force, force2); break; #endif case BONDED_IA_DIHEDRAL: bond_broken = calc_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; #ifdef BOND_CONSTRAINT case BONDED_IA_RIGID_BOND: //add_rigid_bond_pair_force(p1,p2, iaparams, force, force2); bond_broken = 0; force[0]=force[1]=force[2]=0.0; break; #endif #ifdef TABULATED case BONDED_IA_TABULATED: switch(iaparams->p.tab.type) { case TAB_BOND_LENGTH: bond_broken = calc_tab_bond_force(p1, p2, iaparams, dx, force); break; case TAB_BOND_ANGLE: bond_broken = calc_tab_angle_force(p1, p2, p3, iaparams, force, force2); break; case TAB_BOND_DIHEDRAL: bond_broken = calc_tab_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; default: errtxt = runtime_error(128 + ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{081 add_bonded_force: tabulated bond type of atom %d unknown\n", p1->p.identity); return; } break; #endif #ifdef OVERLAPPED case BONDED_IA_OVERLAPPED: switch(iaparams->p.overlap.type) { case OVERLAP_BOND_LENGTH: bond_broken = calc_overlap_bond_force(p1, p2, iaparams, dx, force); break; case OVERLAP_BOND_ANGLE: bond_broken = calc_overlap_angle_force(p1, p2, p3, iaparams, force, force2); break; case OVERLAP_BOND_DIHEDRAL: bond_broken = calc_overlap_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; default: errtxt = runtime_error(128 + ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{081 add_bonded_force: overlapped bond type of atom %d unknown\n", p1->p.identity); return; } break; #endif #ifdef BOND_VIRTUAL case BONDED_IA_VIRTUAL_BOND: bond_broken = 0; force[0]=force[1]=force[2]=0.0; break; #endif default : errtxt = runtime_error(128 + ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt,"{082 add_bonded_force: bond type of atom %d unknown\n", p1->p.identity); return; } switch (n_partners) { case 1: if (bond_broken) { char *errtext = runtime_error(128 + 2*ES_INTEGER_SPACE); ERROR_SPRINTF(errtext,"{083 bond broken between particles %d and %d} ", p1->p.identity, p2->p.identity); continue; } for (j = 0; j < 3; j++) { switch (type) { #ifdef BOND_ENDANGLEDIST case BONDED_IA_ENDANGLEDIST: p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; break; #endif // BOND_ENDANGLEDIST default: 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 } #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO) nptiso.p_vir[j] += force[j] * dx[j]; #endif } break; case 2: if (bond_broken) { char *errtext = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtext,"{084 bond broken between particles %d, %d and %d} ", p1->p.identity, p2->p.identity, p3->p.identity); continue; } for (j = 0; j < 3; j++) { switch (type) { case BONDED_IA_AREA_FORCE_LOCAL: p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; p3->f.f[j] += force3[j]; break; #ifdef AREA_FORCE_GLOBAL case BONDED_IA_AREA_FORCE_GLOBAL: break; #endif #ifdef VOLUME_FORCE case BONDED_IA_VOLUME_FORCE: break; #endif default: p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; p3->f.f[j] -= (force[j] + force2[j]); } } break; case 3: if (bond_broken) { char *errtext = runtime_error(128 + 4*ES_INTEGER_SPACE); ERROR_SPRINTF(errtext,"{085 bond broken between particles %d, %d, %d and %d} ", p1->p.identity, p2->p.identity, p3->p.identity, p4->p.identity); continue; } for (j = 0; j < 3; j++) { switch (type) { case BONDED_IA_BENDING_FORCE: p1->f.f[j] -= (force[j]*0.5+force2[j]*0.5); p2->f.f[j] += force[j]; p3->f.f[j] -= (force[j]*0.5+force2[j]*0.5); p4->f.f[j] += force2[j]; break; default: p1->f.f[j] += force[j]; p2->f.f[j] += force2[j]; p3->f.f[j] += force3[j]; p4->f.f[j] -= (force[j] + force2[j] + force3[j]); } } break; } } }