Program Listing for File pressure_tensor.cpp#

↰ Return to documentation for file (source/pressure_tensor.cpp)

#include "pele/pressure_tensor.hpp"

#include "pele/simple_pairwise_potential.hpp"

namespace pele {

/*
 * computes the static pressure tensor, ignoring the momenta of the atoms
 * the momentum component can be added
 * */
double pressure_tensor(std::shared_ptr<pele::BasePotential> pot_,
                       pele::Array<double> x, pele::Array<double> ptensor,
                       const double volume) {
  pele::PairwisePotentialInterface *pot =
      dynamic_cast<pele::PairwisePotentialInterface *>(pot_.get());
  if (pot == NULL) {
    throw std::runtime_error("pressure_tensor: illegal potential");
  }
  const size_t ndim = pot->get_ndim();
  const size_t natoms = x.size() / ndim;
  if (ndim * natoms != x.size()) {
    throw std::runtime_error("x is not divisible by the number of dimensions");
  }
  if (ptensor.size() != ndim * ndim) {
    throw std::runtime_error("ptensor must have size ndim * ndim");
  }
  double gij;
  double dr[ndim];
  ptensor.assign(0.);
  for (size_t atom_i = 0; atom_i < natoms; ++atom_i) {
    size_t const i1 = ndim * atom_i;
    for (size_t atom_j = 0; atom_j < atom_i; ++atom_j) {
      size_t const j1 = ndim * atom_j;
      pot->get_rij(dr, &x[i1], &x[j1]);
      double r2 = 0;
      for (size_t k = 0; k < ndim; ++k) {
        r2 += dr[k] * dr[k];
      }
      pot->get_interaction_energy_gradient(r2, &gij, atom_i, atom_j);
      for (size_t k = 0; k < ndim; ++k) {
        for (size_t l = k; l < ndim; ++l) {
          ptensor[k * ndim + l] += dr[k] * gij * dr[l];
          ptensor[l * ndim + k] = ptensor[k * ndim + l];
        }
      }
    }
  }
  ptensor /= volume;
  // pressure is the average of the trace of the pressure tensor divided by the
  // volume, here we return only the trace divided by the dimensionality
  double traceP = 0.;
  for (size_t i = 0; i < ndim; ++i) {
    traceP += ptensor[i * ndim + i];
  }
  return traceP / ndim;
}

}  // namespace pele