Пример #1
0
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;
      }
    }
  }
}  
Пример #2
0
/** 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;
    }
  }
}