forked from lijiext/lammps
621 lines
24 KiB
C++
621 lines
24 KiB
C++
#include "Stress.h"
|
|
#include "CauchyBorn.h"
|
|
#include "CBLattice.h"
|
|
#include "CbLjCut.h"
|
|
#include "CbLjSmoothLinear.h"
|
|
#include "CbEam.h"
|
|
#include "ATC_Error.h"
|
|
#include "LammpsInterface.h"
|
|
#include "VoigtOperations.h"
|
|
#include <iostream>
|
|
|
|
using ATC_Utility::command_line;
|
|
using ATC_Utility::str2dbl;
|
|
using voigt3::voigt_idx1;
|
|
using voigt3::voigt_idx2;
|
|
using voigt3::to_voigt_unsymmetric;
|
|
using voigt3::from_voigt_unsymmetric;
|
|
using voigt3::to_voigt;
|
|
using voigt3::from_voigt;
|
|
using std::stringstream;
|
|
using std::vector;
|
|
using std::string;
|
|
using std::fstream;
|
|
|
|
namespace ATC {
|
|
//=============================================================================
|
|
// extracts a stress at an integration point
|
|
// Note: Utility function: not in header
|
|
//=============================================================================
|
|
DENS_MAT extract_stress(const DENS_MAT_VEC &sigma, INDEX ip=0)
|
|
{
|
|
DENS_MAT s(3,3,false);
|
|
for (int j=0; j<3; j++) for (int i=0; i<3; i++) s(i,j) = sigma[i](ip,j);
|
|
return s;
|
|
}
|
|
//=============================================================================
|
|
// computes the pressure from the stress at the first quadrature point (in atm)
|
|
// Note: Utility function: not in header
|
|
//=============================================================================
|
|
double compute_pressure(const DENS_MAT_VEC &sigma, const DENS_MAT &F)
|
|
{
|
|
// pressure in units (mass-velocity^2)/Volume (LAMMPS real)
|
|
double p = (sigma[0](0,0) + sigma[1](0,1) + sigma[2](0,2)) * (1.0/3.0);
|
|
p *= 1.0e14/6.0221415; // convert from units real to Pa
|
|
p *= 1.0/101235.0; // convert from Pa to ATM
|
|
return p * pow(det(F), -1.0/3.0); // convert from PK2 to Cauchy stress
|
|
}
|
|
//=============================================================================
|
|
// extracts the deformation gradient at a quadrature point, q
|
|
// Note: Utility function: not in header
|
|
//=============================================================================
|
|
void deformation_gradient(const DENS_MAT_VEC &du, INDEX q, MATRIX &F)
|
|
{
|
|
F.reset(du.size(), du.size(), false);
|
|
for (INDEX j=0; j<F.nCols(); j++) {
|
|
for (INDEX i=0; i<F.nRows(); i++) F(i,j) = du[j](q,i);
|
|
F(j,j) += 1.0;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
// E = 1/2 stress*strain for linear elastic models
|
|
//=============================================================================
|
|
void Stress::elastic_energy(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT &energy) const
|
|
{
|
|
int nRows = ( ((gradFields.find(DISPLACEMENT))->second)[0]).nRows();
|
|
energy.reset(nRows,1);
|
|
ATC::LammpsInterface::instance()->print_msg("WARNING: returning dummy elastic energy");
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
// isotropic linear elastic
|
|
//=============================================================================
|
|
StressLinearElastic::StressLinearElastic(fstream &fileId)
|
|
: StressCubicElastic(), E_(0), nu_(0), mu_(0), lambda_(0)
|
|
{
|
|
if (!fileId.is_open()) throw ATC_Error("cannot open material file");
|
|
vector<string> line;
|
|
while(fileId.good()) {
|
|
command_line(fileId, line);
|
|
if (line[0] == "end") {
|
|
mu_ = E_/(2.0+2.0*nu_);
|
|
lambda_ = mu_*nu_ / (0.5 - nu_);
|
|
StressCubicElastic::c11_ = E_*(1-nu_)/(1+nu_)/(1-2*nu_);
|
|
StressCubicElastic::c12_ = E_*nu_ /(1+nu_)/(1-2*nu_);
|
|
StressCubicElastic::c44_ = E_/(1+nu_)/2;
|
|
if (nu_ < 0.0 || nu_ > 1.0)
|
|
throw ATC_Error("bad linear elastic constants");
|
|
if (lambda_ < 0.0 || mu_ < 0.0)
|
|
throw ATC_Error("bad continuum material parameter");
|
|
return;
|
|
}
|
|
else if (line[0]=="modulus") E_ = str2dbl(line[1]);
|
|
else if (line[0]=="possions_ratio") nu_ = str2dbl(line[1]);
|
|
else throw ATC_Error( "unrecognized material function");
|
|
}
|
|
}
|
|
//=============================================================================
|
|
// compute the stress at N integration points from the displacement gradient
|
|
// T_{ij} = 1/2*C_{ijkl}* (u_{k,l} + u_{l,k})
|
|
//=============================================================================
|
|
void StressLinearElastic::stress(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT_VEC &sigma)
|
|
{
|
|
GRAD_FIELD_MATS::const_iterator du_itr = gradFields.find(DISPLACEMENT);
|
|
const DENS_MAT_VEC &du = du_itr->second;
|
|
|
|
CLON_VEC uxx(du[0],CLONE_COL,0);
|
|
CLON_VEC uxy(du[1],CLONE_COL,0);
|
|
CLON_VEC uxz(du[2],CLONE_COL,0);
|
|
CLON_VEC uyx(du[0],CLONE_COL,1);
|
|
CLON_VEC uyy(du[1],CLONE_COL,1);
|
|
CLON_VEC uyz(du[2],CLONE_COL,1);
|
|
CLON_VEC uzx(du[0],CLONE_COL,2);
|
|
CLON_VEC uzy(du[1],CLONE_COL,2);
|
|
CLON_VEC uzz(du[2],CLONE_COL,2);
|
|
|
|
const INDEX N = uxx.size(); // # of integration pts
|
|
sigma.assign(3, DENS_MAT(N,3));
|
|
|
|
// precompute the pressure and copy to the diagonal
|
|
column(sigma[0],0) = (uxx + uyy + uzz)*(-lambda_);
|
|
column(sigma[1],1) = column(sigma[0],0);
|
|
column(sigma[2],2) = column(sigma[0],0);
|
|
|
|
column(sigma[0],0) -= 2.0*mu_*uxx;
|
|
column(sigma[0],1) = (uxy + uyx)*(-mu_);
|
|
column(sigma[0],2) = (uxz + uzx)*(-mu_);
|
|
column(sigma[1],0) = column(sigma[0],1);
|
|
column(sigma[1],1) -= 2.0*mu_*uyy;
|
|
column(sigma[1],2) = (uyz + uzy)*(-mu_);
|
|
column(sigma[2],0) = column(sigma[0],2);
|
|
column(sigma[2],1) = column(sigma[1],2);
|
|
column(sigma[2],2) -= 2.0*mu_*uzz;
|
|
}
|
|
//=============================================================================
|
|
// cubic elastic
|
|
//=============================================================================
|
|
StressCubicElastic::StressCubicElastic(fstream &fileId)
|
|
: c11_(0), c12_(0), c44_(0)
|
|
{
|
|
if (!fileId.is_open()) throw ATC_Error("cannot open material file");
|
|
vector<string> line;
|
|
while(fileId.good()) {
|
|
command_line(fileId, line);
|
|
if (line[0]=="end") return;
|
|
else if (line[0]=="c11") c11_ = str2dbl(line[1]);
|
|
else if (line[0]=="c12") c12_ = str2dbl(line[1]);
|
|
else if (line[0]=="c44") c44_ = str2dbl(line[1]);
|
|
else throw ATC_Error( "unrecognized material function");
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
// compute the stress at N integration points from the displacement gradient
|
|
// T_{ij} = 1/2*C_{ijkl}*(u_{k,l} + u_{l,k})
|
|
//---------------------------------------------------------------------------
|
|
void StressCubicElastic::stress(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT_VEC &sigma)
|
|
{
|
|
GRAD_FIELD_MATS::const_iterator du_itr = gradFields.find(DISPLACEMENT);
|
|
const DENS_MAT_VEC &du = du_itr->second;
|
|
CLON_VEC uxx(du[0],CLONE_COL,0);
|
|
CLON_VEC uxy(du[1],CLONE_COL,0);
|
|
CLON_VEC uxz(du[2],CLONE_COL,0);
|
|
CLON_VEC uyx(du[0],CLONE_COL,1);
|
|
CLON_VEC uyy(du[1],CLONE_COL,1);
|
|
CLON_VEC uyz(du[2],CLONE_COL,1);
|
|
CLON_VEC uzx(du[0],CLONE_COL,2);
|
|
CLON_VEC uzy(du[1],CLONE_COL,2);
|
|
CLON_VEC uzz(du[2],CLONE_COL,2);
|
|
|
|
const INDEX N = uxx.size(); // # of integration pts
|
|
sigma.assign(3, DENS_MAT(N,3));
|
|
|
|
const double c12 = c12_;
|
|
const double c11 = c11_;
|
|
const double c44 = c44_;
|
|
|
|
// scaling: stress must return (-) stress
|
|
column(sigma[0],0) = -c11*uxx - c12*(uyy+uzz);
|
|
column(sigma[1],1) = -c11*uyy - c12*(uxx+uzz);
|
|
column(sigma[2],2) = -c11*uzz - c12*(uxx+uyy);
|
|
column(sigma[0],1) = -c44*(uxy+uyx);
|
|
column(sigma[1],0) = column(sigma[0],1);
|
|
column(sigma[0],2) = -c44*(uxz+uzx);
|
|
column(sigma[2],0) = column(sigma[0],2);
|
|
column(sigma[1],2) = -c44*(uyz+uzy);
|
|
column(sigma[2],1) = column(sigma[1],2);
|
|
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
// compute the elastic energy at N integration points from displacement gradient
|
|
// E = 1/8*C_{ijkl}* (u_{k,l} + u_{l,k})* (u_{i,j} + u_{j,i})*rho ?
|
|
// = 1/2 (4 c44 (u12^2 + u13^2 + u23^2) + 2 c12 (u11 u22 + u11 u33 + u22 u33)
|
|
// + c11 (u11^2 + u22^2 + u33^2))
|
|
//---------------------------------------------------------------------------
|
|
void StressCubicElastic::elastic_energy(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT &energy) const
|
|
{
|
|
GRAD_FIELD_MATS::const_iterator du_itr = gradFields.find(DISPLACEMENT);
|
|
const DENS_MAT_VEC &du = du_itr->second;
|
|
CLON_VEC uxx(du[0],CLONE_COL,0);
|
|
CLON_VEC uxy(du[1],CLONE_COL,0);
|
|
CLON_VEC uxz(du[2],CLONE_COL,0);
|
|
CLON_VEC uyx(du[0],CLONE_COL,1);
|
|
CLON_VEC uyy(du[1],CLONE_COL,1);
|
|
CLON_VEC uyz(du[2],CLONE_COL,1);
|
|
CLON_VEC uzx(du[0],CLONE_COL,2);
|
|
CLON_VEC uzy(du[1],CLONE_COL,2);
|
|
CLON_VEC uzz(du[2],CLONE_COL,2);
|
|
|
|
CLON_VEC E(energy,CLONE_COL,0);
|
|
|
|
const double c12 = c12_;
|
|
const double c11 = c11_;
|
|
const double c44 = c44_;
|
|
//double scale = (ATC::LammpsInterface::instance()->mvv2e());
|
|
for (INDEX gp=0; gp<du.front().nRows(); gp++) {
|
|
double u11 = uxx(gp);
|
|
double u22 = uyy(gp);
|
|
double u33 = uzz(gp);
|
|
double u12 = 0.5*(uxy(gp)+uyx(gp));
|
|
double u13 = 0.5*(uxz(gp)+uzx(gp));
|
|
double u23 = 0.5*(uyz(gp)+uzy(gp));
|
|
double EE = 0.5* (4.0*c44*(u12*u12 + u13*u13 + u23*u23)
|
|
+ 2.0*c12*(u11*u22 + u11*u33 + u22*u33)
|
|
+ c11*(u11*u11 + u22*u22 + u33*u33));
|
|
|
|
E(gp) = EE;
|
|
}
|
|
}
|
|
|
|
void StressCubicElastic::set_tangent(void)
|
|
{
|
|
C_.reset(6,6);
|
|
C_(0,0)=C_(1,1)=C_(2,2) =c11_;
|
|
C_(0,1)=C_(1,0)=C_(1,2)=C_(2,1)=C_(0,2)=C_(2,0)=c12_;
|
|
C_(3,3)=C_(4,4)=C_(5,5) =c44_;
|
|
}
|
|
|
|
//=============================================================================
|
|
// damped cubic elastic
|
|
//=============================================================================
|
|
StressCubicElasticDamped::StressCubicElasticDamped(fstream &fileId)
|
|
: StressCubicElastic(), gamma_(0)
|
|
{
|
|
if (!fileId.is_open()) throw ATC_Error("cannot open material file");
|
|
vector<string> line;
|
|
while(fileId.good()) {
|
|
command_line(fileId, line);
|
|
if (line[0]=="end") return;
|
|
else if (line[0]=="c11") StressCubicElastic::c11_ = str2dbl(line[1]);
|
|
else if (line[0]=="c12") StressCubicElastic::c12_ = str2dbl(line[1]);
|
|
else if (line[0]=="c44") StressCubicElastic::c44_ = str2dbl(line[1]);
|
|
else if (line[0]=="gamma") gamma_ = str2dbl(line[1]);
|
|
else throw ATC_Error( "unrecognized material function");
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
// compute the stress at N integration points
|
|
//---------------------------------------------------------------------------
|
|
|
|
void StressCubicElasticDamped::stress(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT_VEC &sigma)
|
|
{
|
|
StressCubicElastic::stress(fields,gradFields,sigma);
|
|
GRAD_FIELD_MATS::const_iterator dv_itr = gradFields.find(VELOCITY);
|
|
const DENS_MAT_VEC &dv = dv_itr->second;
|
|
CLON_VEC vxx(dv[0],CLONE_COL,0);
|
|
CLON_VEC vxy(dv[1],CLONE_COL,0);
|
|
CLON_VEC vxz(dv[2],CLONE_COL,0);
|
|
CLON_VEC vyx(dv[0],CLONE_COL,1);
|
|
CLON_VEC vyy(dv[1],CLONE_COL,1);
|
|
CLON_VEC vyz(dv[2],CLONE_COL,1);
|
|
CLON_VEC vzx(dv[0],CLONE_COL,2);
|
|
CLON_VEC vzy(dv[1],CLONE_COL,2);
|
|
CLON_VEC vzz(dv[2],CLONE_COL,2);
|
|
|
|
// scaling: stress must return (-) stress
|
|
column(sigma[0],0) += -gamma_*vxx;
|
|
column(sigma[1],1) += -gamma_*vyy;
|
|
column(sigma[2],2) += -gamma_*vzz;
|
|
column(sigma[0],1) += -0.5*gamma_*(vxy+vyx);
|
|
column(sigma[1],0) += column(sigma[0],1);
|
|
column(sigma[0],2) += -0.5*gamma_*(vxz+vzx);
|
|
column(sigma[2],0) += column(sigma[0],2);
|
|
column(sigma[1],2) += -0.5*gamma_*(vyz+vzy);
|
|
column(sigma[2],1) += column(sigma[1],2);
|
|
}
|
|
//==============================================================================
|
|
// cauchy born model
|
|
//==============================================================================
|
|
StressCauchyBorn::StressCauchyBorn(fstream &fileId, CbData &cb)
|
|
: cblattice_(NULL),
|
|
potential_(NULL),
|
|
makeLinear_(false),
|
|
cubicMat_(NULL),
|
|
initialized_(false),
|
|
fixed_temperature_(0.),
|
|
cbdata_(cb)
|
|
{
|
|
if (!fileId.is_open()) throw ATC_Error("cannot open material file");
|
|
while(fileId.good()) {
|
|
// reads a line from the material file
|
|
vector<string> line;
|
|
command_line(fileId, line);
|
|
if (line.empty()) continue; // skip blank lines
|
|
else if (line[0]=="end") {
|
|
delete cblattice_;
|
|
if (!potential_) throw ATC_Error( "no potential defined");
|
|
cblattice_ = new CBLattice(cbdata_.cell_vectors, cbdata_.basis_vectors);
|
|
return;
|
|
}
|
|
else if (line[0] == "pair_style") {
|
|
if (line[1] == "lj/cut") { // Lennard-Jones w/ cutoff radius
|
|
if (line.size()<3) throw(ATC_Error("no lj/cut cutoff radius"));
|
|
const double rc = str2dbl(line[2]);
|
|
while (!fileId.eof()) { // find next pair_coeff command
|
|
command_line(fileId, line);
|
|
if (line.size() && line[0]=="pair_coeff") break;
|
|
}
|
|
if (line[0] != "pair_coeff" || line.size() != 3) {
|
|
throw(ATC_Error("lj/cut needs 2 coefficents"));
|
|
}
|
|
delete potential_;
|
|
potential_ = new CbLjCut(str2dbl(line[1]), str2dbl(line[2]), rc);
|
|
}
|
|
else if (line[1] == "lj/smooth/linear") { // Lennard-Jones w/ cutoff radius and smoothed
|
|
if (line.size()<3) throw(ATC_Error("no lj/smooth/linear cutoff radius"));
|
|
const double rc = str2dbl(line[2]);
|
|
while (!fileId.eof()) { // find next pair_coeff command
|
|
command_line(fileId, line);
|
|
if (line.size() && line[0]=="pair_coeff") break;
|
|
}
|
|
if (line[0] != "pair_coeff" || line.size() != 3) {
|
|
throw(ATC_Error("lj/smooth/linear needs 2 coefficents"));
|
|
}
|
|
delete potential_;
|
|
potential_ = new CbLjSmoothLinear(str2dbl(line[1]), str2dbl(line[2]), rc);
|
|
}
|
|
else if (line[1] == "eam") { // Embedded atom method potential
|
|
delete potential_;
|
|
potential_ = new CbEam();
|
|
}
|
|
else throw (ATC_Error("Invalid pair style"));
|
|
}
|
|
else if (line[0] == "linear") makeLinear_ = true;
|
|
else if (line[0] == "temperature" && line.size() == 2) {
|
|
fixed_temperature_ = str2dbl(line[1]);
|
|
}
|
|
else if (line[0]=="material" || line[0]=="stress") /* ignore this */;
|
|
else throw ATC_Error( "Unrecognized Cauchy-Born parameter: "+line[0]+".");
|
|
}
|
|
|
|
}
|
|
//==============================================================================
|
|
//* default destructor - delete potential and lattice
|
|
//==============================================================================
|
|
StressCauchyBorn::~StressCauchyBorn()
|
|
{
|
|
if (potential_) delete potential_;
|
|
if (cblattice_) delete cblattice_;
|
|
if (cubicMat_) delete cubicMat_;
|
|
}
|
|
|
|
//==============================================================================
|
|
// initialize
|
|
//==============================================================================
|
|
void StressCauchyBorn::initialize(void)
|
|
{
|
|
if (!initialized_) {
|
|
if (makeLinear_) linearize();
|
|
|
|
stringstream ss;
|
|
double k = stiffness()*cbdata_.e2mvv;
|
|
double m = cbdata_.atom_mass;
|
|
double w0 = sqrt(k*m);
|
|
ss << "CB stiffness: " << stiffness() << " Einstein freq: " << w0;
|
|
ATC::LammpsInterface::instance()->print_msg_once(ss.str());
|
|
|
|
initialized_ = true;
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// compute the bond stiffness consistent with the einstein freq
|
|
//==============================================================================
|
|
double StressCauchyBorn::stiffness(void) const
|
|
{
|
|
AtomCluster vac;
|
|
cblattice_->atom_cluster(eye<double>(3,3), potential_->cutoff_radius(), vac);
|
|
DENS_MAT k = vac.force_constants(0,potential_);
|
|
return k(0,0);
|
|
}
|
|
//==============================================================================
|
|
// compute the stress at N integration points from the displacement gradient
|
|
//==============================================================================
|
|
void StressCauchyBorn::stress(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT_VEC &sigma)
|
|
{
|
|
if (cubicMat_) {
|
|
cubicMat_->stress(fields, gradFields, sigma);
|
|
return;
|
|
}
|
|
FIELD_MATS::const_iterator temp = fields.find(TEMPERATURE);
|
|
GRAD_FIELD_MATS::const_iterator disp_gradient = gradFields.find(DISPLACEMENT);
|
|
|
|
// Scaling factor - scale by atomic volume and energy conversion.
|
|
// negative because stress must return (-) stress
|
|
const double fact = -cbdata_.inv_atom_volume * cbdata_.e2mvv;
|
|
const DENS_MAT_VEC &du(disp_gradient->second);
|
|
const INDEX num_integration_pts = du.front().nRows();
|
|
const INDEX nsd = du.size();
|
|
DENS_MAT F(nsd,nsd); // displacement gradient
|
|
bool temp_varies = (temp != fields.end());
|
|
sigma.assign(nsd, DENS_MAT(num_integration_pts, nsd));
|
|
StressAtIP S(sigma); // wrapper for quadrature points.
|
|
AtomCluster vac;
|
|
|
|
for (INDEX gp=0; gp<num_integration_pts; gp++) {
|
|
// Sets the quadrature point to be computed.
|
|
S.set_quadrature_point(gp);
|
|
// Get displacement gradient and construct a virtual atom cluster.
|
|
deformation_gradient(du, gp, F);
|
|
// Generates the atom cluster, given the deformation gradient.
|
|
cblattice_->atom_cluster(F, potential_->cutoff_radius(), vac);
|
|
// Get temperature (assume 0K if no temperature field is present).
|
|
const double T = (temp_varies ? temp->second[gp] : fixed_temperature_);
|
|
// Computes the cauchy-born stresses.
|
|
const StressArgs args(vac, potential_, cbdata_.boltzmann, cbdata_.hbar, T);
|
|
cb_stress(args, S);
|
|
|
|
// copy symmetric part of stress and scale by V0
|
|
for (INDEX i=0; i<nsd; i++) {
|
|
S(i,i) *= fact;
|
|
for (INDEX j=i+1; j<nsd; j++) S(j,i)=(S(i,j)*=fact);
|
|
}
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// Computes free (T>0)/potential(T=0) energy density. [mvv/L^3]
|
|
//==============================================================================
|
|
void StressCauchyBorn::elastic_energy(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT &energy) const
|
|
{
|
|
if (cubicMat_) {
|
|
cubicMat_->elastic_energy(fields, gradFields, energy);
|
|
return;
|
|
}
|
|
FIELD_MATS::const_iterator temp = fields.find(TEMPERATURE);
|
|
GRAD_FIELD_MATS::const_iterator disp_gradient = gradFields.find(DISPLACEMENT);
|
|
const DENS_MAT_VEC &du(disp_gradient->second);
|
|
DENS_MAT F(du.size(),du.size());
|
|
AtomCluster vac;
|
|
|
|
for (INDEX gp=0; gp<du.front().nRows(); gp++) {
|
|
deformation_gradient(du, gp, F);
|
|
cblattice_->atom_cluster(F, potential_->cutoff_radius(), vac);
|
|
double T = (temp!=fields.end() ? temp->second[gp] : fixed_temperature_);
|
|
energy[gp] = cb_energy(StressArgs(vac, potential_, cbdata_.boltzmann, cbdata_.hbar, T));
|
|
}
|
|
// Scaling factor - scale by atomic volume and energy conversion.
|
|
|
|
energy *= cbdata_.inv_atom_volume * cbdata_.e2mvv;
|
|
}
|
|
|
|
//==============================================================================
|
|
// Computes entropic energy density. [mvv/L^3]
|
|
//==============================================================================
|
|
void StressCauchyBorn::entropic_energy(const FIELD_MATS &fields,
|
|
const GRAD_FIELD_MATS &gradFields,
|
|
DENS_MAT &energy) const
|
|
{
|
|
FIELD_MATS::const_iterator temp = fields.find(TEMPERATURE);
|
|
GRAD_FIELD_MATS::const_iterator disp_gradient = gradFields.find(DISPLACEMENT);
|
|
const DENS_MAT_VEC &du(disp_gradient->second);
|
|
DENS_MAT F(du.size(),du.size());
|
|
AtomCluster vac;
|
|
|
|
for (INDEX gp=0; gp<du.front().nRows(); gp++) {
|
|
deformation_gradient(du, gp, F);
|
|
cblattice_->atom_cluster(F, potential_->cutoff_radius(), vac);
|
|
double T = (temp!=fields.end() ? temp->second[gp] : fixed_temperature_);
|
|
energy[gp] = cb_entropic_energy(StressArgs(vac, potential_, cbdata_.boltzmann, cbdata_.hbar, T));
|
|
}
|
|
// Scaling factor - scale by atomic volume and energy conversion.
|
|
energy *= cbdata_.inv_atom_volume * cbdata_.e2mvv;
|
|
}
|
|
|
|
//==============================================================================
|
|
// creates a linearization for a deformation gradient
|
|
//==============================================================================
|
|
void StressCauchyBorn::linearize(MATRIX *F)
|
|
{
|
|
if (cubicMat_) delete cubicMat_;
|
|
DENS_MAT C;
|
|
if (F) tangent(*F, C);
|
|
else tangent(eye<double>(3,3), C);
|
|
cubicMat_ = new StressCubicElastic(C(0,0), C(0,1), C(3,3));
|
|
|
|
stringstream ss;
|
|
double c11 = C(0,0)/cbdata_.e2mvv;
|
|
double c12 = C(0,1)/cbdata_.e2mvv;
|
|
double c44 = C(3,3)/cbdata_.e2mvv;
|
|
ss << "created cubic stress function:"
|
|
<< "\n lammps ATC units"
|
|
<< "\n c11=" << c11 << " " << C(0,0)
|
|
<< "\n c12=" << c12 << " " << C(0,1)
|
|
<< "\n c44=" << c44 << " " << C(3,3);
|
|
ATC::LammpsInterface::instance()->print_msg_once(ss.str());
|
|
}
|
|
//==============================================================================
|
|
// sets C as the material tangent modulus, given deformation gradient F
|
|
//==============================================================================
|
|
// Note: C is dS/dC which is 1/2 dS/dF_sym
|
|
|
|
void StressCauchyBorn::tangent(const MATRIX &F, MATRIX &C) const
|
|
{
|
|
if (cubicMat_) {
|
|
cubicMat_->tangent(F,C);
|
|
return;
|
|
}
|
|
elasticity_tensor(F,C);
|
|
}
|
|
//==============================================================================
|
|
// 1st elasticity tensor : B = dP/dF = C F F + S I ( 9 x 9 in Voigt notation)
|
|
// 2nd elasticity tensor : C = dS/dE ( 6 x 6 in Voigt notation)
|
|
//==============================================================================
|
|
DENS_VEC StressCauchyBorn::elasticity_tensor(const VECTOR &Fv, MATRIX &C, const ElasticityTensorType type) const
|
|
{
|
|
DENS_MAT F;
|
|
if (Fv.nRows()==9) { F = from_voigt_unsymmetric(Fv); }
|
|
else { F = from_voigt(Fv); }
|
|
return elasticity_tensor(F, C,type);
|
|
}
|
|
DENS_VEC StressCauchyBorn::elasticity_tensor(const MATRIX &F, MATRIX &C, const ElasticityTensorType type) const
|
|
{
|
|
double T = 0;
|
|
AtomCluster vac;
|
|
cblattice_->atom_cluster(F, potential_->cutoff_radius(), vac);
|
|
if (vac.size() < 4) throw ATC_Error("StressCauchyBorn::second_elasticity_tensor cluster does not have sufficient atoms");
|
|
const StressArgs args(vac, potential_, cbdata_.boltzmann, cbdata_.hbar, T);
|
|
// if using EAM potential, calculate embedding function and derivatives
|
|
bool hasEAM = potential_->terms.embedding;
|
|
double embed_p = 0;
|
|
double embed_pp = 0;
|
|
if (hasEAM) {
|
|
double e_density = cb_electron_density(args);
|
|
embed_p = potential_->F_p(e_density); // "F" in usual EAM symbology
|
|
embed_pp = potential_->F_pp(e_density);
|
|
}
|
|
|
|
|
|
int size = 6;
|
|
if (type == FIRST_ELASTICITY_TENSOR) { size = 9; }
|
|
DENS_VEC Z(size), S(size), Zfp(size);
|
|
Zfp = 0;
|
|
C.reset(size,size);
|
|
for (INDEX a=0; a<vac.size(); a++) {
|
|
const DENS_VEC &Ra = vac.R(a);
|
|
if (type == FIRST_ELASTICITY_TENSOR) {
|
|
DENS_VEC ra = F*Ra;
|
|
for (INDEX i=0; i<size; i++) { Z(i)=ra(voigt_idx1[i])*Ra(voigt_idx2[i]); }
|
|
}
|
|
else {
|
|
for (INDEX i=0; i<size; i++) { Z(i)=Ra(voigt_idx1[i])*Ra(voigt_idx2[i]); }
|
|
}
|
|
double d = vac.bond_length(a);
|
|
double rinv = 1.0/d;
|
|
double phi_r = potential_->phi_r(d); // computes phi'
|
|
double phi_rr = potential_->phi_rr(d); // computes phi''
|
|
double fact1 = 0.5*phi_r*rinv; // 1/2 see Philips
|
|
double fact2 = 0.5*(phi_rr - phi_r*rinv) * rinv*rinv;
|
|
if (hasEAM) {
|
|
double rho_r = potential_->rho_r(d); // computes rho'
|
|
double rho_rr = potential_->rho_rr(d); // computes rho''
|
|
fact1 += embed_p*rho_r*rinv;
|
|
fact2 += embed_p*(rho_rr - rho_r*rinv) * rinv*rinv;
|
|
Zfp += Z*(rho_r*rinv);
|
|
}
|
|
for (INDEX i=0; i<size; i++) {
|
|
S(i) += fact1*Z(i);
|
|
for (INDEX j=0; j<size; j++) {
|
|
C(i,j) += fact2*Z(i)*Z(j);
|
|
}
|
|
}
|
|
if (type == FIRST_ELASTICITY_TENSOR) {
|
|
for (INDEX i=0; i<9; i++) {
|
|
for (INDEX j=0; j<9; j++) {
|
|
if ( voigt_idx1[i] == voigt_idx1[j] ) { // \delta_ik S_JL
|
|
C(i,j) += fact1*Ra(voigt_idx2[i])*Ra(voigt_idx2[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hasEAM) {
|
|
for (INDEX i=0; i<6; i++) {
|
|
for (INDEX j=0; j<6; j++) {
|
|
C(i,j) += embed_pp*Zfp(i)*Zfp(j);
|
|
}
|
|
}
|
|
}
|
|
double s = cbdata_.inv_atom_volume * cbdata_.e2mvv;
|
|
S *= s;
|
|
C *= s;
|
|
return S;
|
|
}
|
|
}// end atc namespace
|