template < typename _AngularPotential > inline real
    FixedTripleAngleListInteractionTemplate < _AngularPotential >::
    computeVirial() {
      LOG4ESPP_INFO(theLogger, "compute scalar virial of the triples");

      const bc::BC& bc = *getSystemRef().bc;
      real w = 0.0;
      for (FixedTripleAngleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it) {
        const Particle &p1 = *it->first;
        const Particle &p2 = *it->second;
        const Particle &p3 = *it->third;
        //const Potential &potential = getPotential(p1.type(), p2.type());
        const espresso::bc::BC& bc = *getSystemRef().bc;
        Real3D dist12, dist32;
        bc.getMinimumImageVectorBox(dist12, p1.position(), p2.position());
        bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
        Real3D force12, force32;

        real currentAngle = fixedtripleList->getAngle(p1.getId(), p2.getId(), p3.getId());
        
        potential->_computeForce(force12, force32, dist12, dist32, currentAngle);
        w += dist12 * force12 + dist32 * force32;
      }
      real wsum;
      boost::mpi::all_reduce(*mpiWorld, w, wsum, std::plus<real>());
      return wsum;
    }
inline void
FixedTripleListTypesInteractionTemplate<_Potential>::computeVirialTensor(Tensor &w) {
  LOG4ESPP_INFO(theLogger, "compute the virial tensor for the FixedTriple List");

  Tensor wlocal(0.0);
  const bc::BC& bc = *getSystemRef().bc;
  for (FixedTripleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it) {
    const Particle &p1 = *it->first;
    const Particle &p2 = *it->second;
    const Particle &p3 = *it->third;
    int type1 = p1.type();
    int type2 = p2.type();
    int type3 = p3.type();
    const Potential &potential = getPotential(type1, type2, type3);
    Real3D r12, r32;
    bc.getMinimumImageVectorBox(r12, p1.position(), p2.position());
    bc.getMinimumImageVectorBox(r32, p3.position(), p2.position());
    Real3D force12, force32;
    potential._computeForce(force12, force32, r12, r32);
    wlocal += Tensor(r12, force12) + Tensor(r32, force32);
  }

  // reduce over all CPUs
  Tensor wsum(0.0);
  boost::mpi::all_reduce(*mpiWorld, wlocal, wsum, std::plus<Tensor>());
  w += wsum;
}
inline real
FixedTripleListTypesInteractionTemplate<_Potential>::
computeVirial() {
  LOG4ESPP_INFO(theLogger, "compute the virial for the FixedTriple List with types");

  real w = 0.0;
  const bc::BC &bc = *getSystemRef().bc;  // boundary conditions
  for (FixedTripleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it) {
    const Particle &p1 = *it->first;
    const Particle &p2 = *it->second;
    const Particle &p3 = *it->third;
    int type1 = p1.type();
    int type2 = p2.type();
    int type3 = p3.type();
    const Potential &potential = getPotential(type1, type2, type3);

    Real3D dist12, dist32;
    bc.getMinimumImageVectorBox(dist12, p1.position(), p2.position());
    bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
    Real3D force12, force32;
    potential._computeForce(force12, force32, dist12, dist32);
    w += dist12 * force12 + dist32 * force32;
  }

  // reduce over all CPUs
  real wsum;
  boost::mpi::all_reduce(*mpiWorld, w, wsum, std::plus<real>());
  return wsum;
}
inline real
FixedTripleListTypesInteractionTemplate<_Potential>::
computeEnergy() {
  LOG4ESPP_INFO(theLogger, "compute energy of the FixedTriple list pairs");

  real e = 0.0;
  const bc::BC &bc = *getSystemRef().bc;  // boundary conditions
  for (FixedTripleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it) {
    const Particle &p1 = *it->first;
    const Particle &p2 = *it->second;
    const Particle &p3 = *it->third;
    int type1 = p1.type();
    int type2 = p2.type();
    int type3 = p3.type();

    const Potential &potential = getPotential(type1, type2, type3);

    Real3D dist12 = bc.getMinimumImageVector(p1.position(), p2.position());
    Real3D dist32 = bc.getMinimumImageVector(p3.position(), p2.position());
    e += potential._computeEnergy(dist12, dist32);
    LOG4ESPP_TRACE(theLogger, "id1=" << p1.id() << " id2="
        << p2.id() << " id3=" << p3.id() << " potential energy=" << e);
  }

  // reduce over all CPUs
  real esum;
  boost::mpi::all_reduce(*mpiWorld, e, esum, std::plus<real>());
  return esum;
}
    inline void
    FixedQuadrupleListInteractionTemplate < _DihedralPotential >::
    computeVirialTensor(Tensor& w) {
      LOG4ESPP_INFO(theLogger, "compute the virial tensor of the quadruples");
    
      Tensor wlocal(0.0);
      const bc::BC& bc = *getSystemRef().bc;

      for (FixedQuadrupleList::QuadrupleList::Iterator it(*fixedquadrupleList); it.isValid(); ++it) {
        const Particle &p1 = *it->first;
        const Particle &p2 = *it->second;
        const Particle &p3 = *it->third;
        const Particle &p4 = *it->fourth;

        Real3D dist21, dist32, dist43; 

        bc.getMinimumImageVectorBox(dist21, p2.position(), p1.position());
        bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
        bc.getMinimumImageVectorBox(dist43, p4.position(), p3.position());

        Real3D force1, force2, force3, force4;

        potential->_computeForce(force1, force2, force3, force4,
                                dist21, dist32, dist43);

        // TODO: formulas are not correct yet

        wlocal += Tensor(dist21, force1) - Tensor(dist32, force2);
      }
      // reduce over all CPUs
      Tensor wsum(0.0);
      boost::mpi::all_reduce(*mpiWorld, (double*)&wlocal, 6, (double*)&wsum, std::plus<double>());
      w += wsum;
    }
    inline real
    FixedQuadrupleListInteractionTemplate < _DihedralPotential >::
    computeVirial() {
      LOG4ESPP_INFO(theLogger, "compute scalar virial of the quadruples");

      real w = 0.0;
      const bc::BC& bc = *getSystemRef().bc;  // boundary conditions
      for (FixedQuadrupleList::QuadrupleList::Iterator it(*fixedquadrupleList); it.isValid(); ++it) {
        const Particle &p1 = *it->first;
        const Particle &p2 = *it->second;
        const Particle &p3 = *it->third;
        const Particle &p4 = *it->fourth;

        Real3D dist21, dist32, dist43; 

        bc.getMinimumImageVectorBox(dist21, p2.position(), p1.position());
        bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
        bc.getMinimumImageVectorBox(dist43, p4.position(), p3.position());

        Real3D force1, force2, force3, force4;

        potential->_computeForce(force1, force2, force3, force4,
                                dist21, dist32, dist43);

        // TODO: formulas are not correct yet?

        w += dist21 * force1 + dist32 * force2;
      }
      
      real wsum;
      boost::mpi::all_reduce(*mpiWorld, w, wsum, std::plus<real>());
      return w;
    }
    inline real
    FixedQuadrupleListInteractionTemplate < _DihedralPotential >::
    computeEnergy() {
      LOG4ESPP_INFO(theLogger, "compute energy of the quadruples");

      const bc::BC& bc = *getSystemRef().bc;  // boundary conditions
      real e = 0.0;
      for (FixedQuadrupleList::QuadrupleList::Iterator it(*fixedquadrupleList); it.isValid(); ++it) {
        const Particle &p1 = *it->first;
        const Particle &p2 = *it->second;
        const Particle &p3 = *it->third;
        const Particle &p4 = *it->fourth;

        Real3D dist21, dist32, dist43; // 

        bc.getMinimumImageVectorBox(dist21, p2.position(), p1.position());
        bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
        bc.getMinimumImageVectorBox(dist43, p4.position(), p3.position());

        e += potential->_computeEnergy(dist21, dist32, dist43);
      }
      real esum;
      boost::mpi::all_reduce(*mpiWorld, e, esum, std::plus<real>());
      return esum;
    }
    //////////////////////////////////////////////////
    // INLINE IMPLEMENTATION
    //////////////////////////////////////////////////
    template < typename _DihedralPotential > inline void
    FixedQuadrupleListInteractionTemplate < _DihedralPotential >::
    addForces() {

      LOG4ESPP_INFO(theLogger, "add forces computed by FixedQuadrupleList");

      const bc::BC& bc = *getSystemRef().bc;  // boundary conditions

      for (FixedQuadrupleList::QuadrupleList::Iterator it(*fixedquadrupleList); it.isValid(); ++it) {
        Particle &p1 = *it->first;
        Particle &p2 = *it->second;
        Particle &p3 = *it->third;
        Particle &p4 = *it->fourth;

        Real3D dist21, dist32, dist43; // 

        bc.getMinimumImageVectorBox(dist21, p2.position(), p1.position());
        bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
        bc.getMinimumImageVectorBox(dist43, p4.position(), p3.position());

	    Real3D force1, force2, force3, force4;  // result forces

	    potential->_computeForce(force1, force2, force3, force4,
                                dist21, dist32, dist43);
        p1.force() += force1;
        p2.force() += force2; //p2.force() -= force2;
        p3.force() += force3;
        p4.force() += force4;
      }
    }
    template < typename _AngularPotential > inline void
    FixedTripleAngleListInteractionTemplate < _AngularPotential >::
    computeVirialTensor(Tensor& w) {
      LOG4ESPP_INFO(theLogger, "compute the virial tensor of the triples");

      Tensor wlocal(0.0);
      const bc::BC& bc = *getSystemRef().bc;
      for (FixedTripleAngleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it){
        const Particle &p1 = *it->first;
        const Particle &p2 = *it->second;
        const Particle &p3 = *it->third;
        //const Potential &potential = getPotential(0, 0);
        Real3D r12, r32;
        bc.getMinimumImageVectorBox(r12, p1.position(), p2.position());
        bc.getMinimumImageVectorBox(r32, p3.position(), p2.position());
        Real3D force12, force32;

        real currentAngle = fixedtripleList->getAngle(p1.getId(), p2.getId(), p3.getId());
        
        potential->_computeForce(force12, force32, r12, r32, currentAngle);
        wlocal += Tensor(r12, force12) + Tensor(r32, force32);
      }
      
      // reduce over all CPUs
      Tensor wsum(0.0);
      boost::mpi::all_reduce(*mpiWorld, (double*)&wlocal,6, (double*)&wsum, std::plus<double>());
      w += wsum;
    }
    template < typename _Potential > inline real
    FixedPairListTypesInteractionTemplate < _Potential >::
    computeVirial() {
      LOG4ESPP_INFO(theLogger, "compute the virial for the Fixed Pair List with types");
      std::cout << "Warning! computeVirial in FixedPairListTypesInteractionTemplate has not been tested." << std::endl;
      
      real w = 0.0;
      const bc::BC& bc = *getSystemRef().bc;  // boundary conditions
      for (FixedPairList::PairList::Iterator it(*fixedpairList);
           it.isValid(); ++it) {          
        Particle &p1 = *it->first;                                       
        Particle &p2 = *it->second;                                      
        int type1 = p1.type();                                           
        int type2 = p2.type();
        const Potential &potential = getPotential(type1, type2);
        // shared_ptr<Potential> potential = getPotential(type1, type2);

        Real3D force(0.0, 0.0, 0.0);
        Real3D r21;
        bc.getMinimumImageVectorBox(r21, p1.position(), p2.position());
        if(potential._computeForce(force, p1, p2, r21)) {
        // if(potential->_computeForce(force, p1, p2)) {
          //Real3D r21 = p1.position() - p2.position();
          w = w + r21 * force;
        }
      }

      // reduce over all CPUs
      real wsum;
      boost::mpi::all_reduce(*mpiWorld, w, wsum, std::plus<real>());
      return wsum; 
    }
    inline real
    FixedPairListTypesInteractionTemplate < _Potential >::
    computeEnergy() {
      LOG4ESPP_INFO(theLogger, "compute energy of the FixedPair list pairs");

      real e = 0.0;
      real es = 0.0;
      const bc::BC& bc = *getSystemRef().bc;  // boundary conditions
      for (FixedPairList::PairList::Iterator it(*fixedpairList);
           it.isValid(); ++it) {
        Particle &p1 = *it->first;
        Particle &p2 = *it->second;
        int type1 = p1.type();
        int type2 = p2.type();
        const Potential &potential = getPotential(type1, type2);
        // shared_ptr<Potential> potential = getPotential(type1, type2);
        Real3D r21;
        bc.getMinimumImageVectorBox(r21, p1.position(), p2.position());
        //e   = potential._computeEnergy(p1, p2);
        // e   = potential->_computeEnergy(p1, p2);
        e = potential._computeEnergy(p1,p2,r21);
        es += e;
        LOG4ESPP_TRACE(theLogger, "id1=" << p1.id() << " id2=" << p2.id() << " potential energy=" << e);
        //std::cout << "id1=" << p1.id() << " id2=" << p2.id() << " potential energy=" << e << std::endl;
      }

      // reduce over all CPUs
      real esum;
      boost::mpi::all_reduce(*mpiWorld, es, esum, std::plus<real>());
      return esum;
    }
    //////////////////////////////////////////////////
    // INLINE IMPLEMENTATION
    //////////////////////////////////////////////////
    template < typename _Potential > inline void
    FixedPairListTypesInteractionTemplate < _Potential >::addForces() {
      LOG4ESPP_INFO(theLogger, "add forces computed by the FixedPair List");
      const bc::BC& bc = *getSystemRef().bc;

      for (FixedPairList::PairList::Iterator it(*fixedpairList); it.isValid(); ++it) {
        Particle &p1 = *it->first;
        Particle &p2 = *it->second;
        int type1 = p1.type();
        int type2 = p2.type();
        const Potential &potential = getPotential(type1, type2);
        // shared_ptr<Potential> potential = getPotential(type1, type2);

        Real3D force(0.0);
        //if(potential._computeForce(force, p1, p2)) {
        ////if(potential->_computeForce(force, p1, p2)) {
        //  p1.force() += force;
        //  p2.force() -= force;
        //  LOG4ESPP_TRACE(theLogger, "id1=" << p1.id() << " id2=" << p2.id() << " force=" << force);
        //}
        Real3D dist;
        bc.getMinimumImageVectorBox(dist, p1.position(), p2.position());
        if(potential._computeForce(force, p1, p2, dist)) {
          p1.force() += force;
          p2.force() -= force;
        }
      }
    }
inline void
FixedQuadrupleListTypesInteractionTemplate<_DihedralPotential>::
computeVirialTensor(Tensor &w, real z) {
    LOG4ESPP_INFO(theLogger, "compute the virial tensor of the quadruples");

    Tensor wlocal(0.0);
    const bc::BC &bc = *getSystemRef().bc;

    std::cout << "Warning!!! computeVirialTensor in specified volume doesn't work for "
              "FixedQuadrupleListTypesInteractionTemplate at the moment" << std::endl;

    for (FixedQuadrupleList::QuadrupleList::Iterator it(*fixedquadrupleList); it.isValid(); ++it) {
        const Particle &p1 = *it->first;
        const Particle &p2 = *it->second;
        const Particle &p3 = *it->third;
        const Particle &p4 = *it->fourth;

        longint type1 = p1.type();
        longint type2 = p2.type();
        longint type3 = p3.type();
        longint type4 = p4.type();

        const Potential &potential = getPotential(type1, type2, type3, type4);

        Real3D dist21, dist32, dist43;

        bc.getMinimumImageVectorBox(dist21, p2.position(), p1.position());
        bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
        bc.getMinimumImageVectorBox(dist43, p4.position(), p3.position());

        Real3D force1, force2, force3, force4;

        potential.computeForce(force1, force2, force3, force4,
                               dist21, dist32, dist43);

        // TODO: formulas are not correct yet

        wlocal += Tensor(dist21, force1) - Tensor(dist32, force2);
    }
    // reduce over all CPUs
    Tensor wsum(0.0);
    boost::mpi::all_reduce(*mpiWorld, (double *) &wlocal, 6, (double *) &wsum, std::plus<double>());
    w += wsum;
}
    template < typename _AngularPotential > inline real
    FixedTripleAngleListInteractionTemplate < _AngularPotential >::
    computeEnergy() {
      LOG4ESPP_INFO(theLogger, "compute energy of the triples");

      const bc::BC& bc = *getSystemRef().bc;
      real e = 0.0;
      for (FixedTripleAngleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it) {
        const Particle &p1 = *it->first;
        const Particle &p2 = *it->second;
        const Particle &p3 = *it->third;
        //const Potential &potential = getPotential(p1.type(), p2.type());
        Real3D dist12 = bc.getMinimumImageVector(p1.position(), p2.position());
        Real3D dist32 = bc.getMinimumImageVector(p3.position(), p2.position());
        
        real currentAngle = fixedtripleList->getAngle(p1.getId(), p2.getId(), p3.getId());
        
        e += potential->_computeEnergy(dist12, dist32, currentAngle);
      }
      real esum;
      boost::mpi::all_reduce(*mpiWorld, e, esum, std::plus<real>());
      return esum;
    }
 //////////////////////////////////////////////////
 // INLINE IMPLEMENTATION
 //////////////////////////////////////////////////
 template < typename _AngularPotential > inline void
 FixedTripleAngleListInteractionTemplate <_AngularPotential>::
 addForces() {
   LOG4ESPP_INFO(theLogger, "add forces computed by FixedTripleAngleList");
   const bc::BC& bc = *getSystemRef().bc;  // boundary conditions
   for (FixedTripleAngleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it) {
     Particle &p1 = *it->first;
     Particle &p2 = *it->second;
     Particle &p3 = *it->third;
     //const Potential &potential = getPotential(p1.type(), p2.type());
     Real3D dist12, dist32;
     bc.getMinimumImageVectorBox(dist12, p1.position(), p2.position());
     bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
     Real3D force12, force32;
     
     real currentAngle = fixedtripleList->getAngle(p1.getId(), p2.getId(), p3.getId());
     
     potential->_computeForce(force12, force32, dist12, dist32, currentAngle);
     p1.force() += force12;
     p2.force() -= force12 + force32;
     p3.force() += force32;
   }
 }
inline void
FixedTripleListTypesInteractionTemplate<_Potential>::addForces() {
  LOG4ESPP_INFO(theLogger, "add forces computed by the FixedTriple List");
  const bc::BC &bc = *getSystemRef().bc;

  for (FixedTripleList::TripleList::Iterator it(*fixedtripleList); it.isValid(); ++it) {
    Particle &p1 = *it->first;
    Particle &p2 = *it->second;
    Particle &p3 = *it->third;
    int type1 = p1.type();
    int type2 = p2.type();
    int type3 = p3.type();
    const Potential &potential = getPotential(type1, type2, type3);

    Real3D dist12, dist32;
    bc.getMinimumImageVectorBox(dist12, p1.position(), p2.position());
    bc.getMinimumImageVectorBox(dist32, p3.position(), p2.position());
    Real3D force12, force32;
    potential._computeForce(force12, force32, dist12, dist32);
    p1.force() += force12;
    p2.force() -= force12 + force32;
    p3.force() += force32;
  }
}