forked from lijiext/lammps
573 lines
21 KiB
C++
573 lines
21 KiB
C++
#include "CauchyBorn.h"
|
|
#include "VoigtOperations.h"
|
|
#include "CBLattice.h"
|
|
#include "CbPotential.h"
|
|
|
|
using voigt3::to_voigt;
|
|
|
|
namespace ATC {
|
|
//============================================================================
|
|
// Computes the electron density for EAM potentials
|
|
//============================================================================
|
|
double cb_electron_density(const StressArgs &args )
|
|
{
|
|
double e_density = 0.0;
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
PairParam pair(args.vac.R(a), args.vac.bond_length(a));
|
|
e_density += args.potential->rho(pair.d);
|
|
}
|
|
return e_density;
|
|
}
|
|
//============================================================================
|
|
// Computes the stress at a quadrature point
|
|
//============================================================================
|
|
void cb_stress(const StressArgs &args, StressAtIP &s, double *F)
|
|
{
|
|
const double &T = args.temperature;
|
|
const bool finite_temp = T > 0.0;
|
|
DENS_MAT D; // dynamical matrix (finite temp)
|
|
DENS_MAT_VEC dDdF; // derivative of dynamical matrix (finite temp)
|
|
double e_density(0.),embed(0.),embed_p(0.),embed_pp(0.),embed_ppp(0.);
|
|
DENS_VEC l0;
|
|
DENS_MAT L0;
|
|
DENS_MAT_VEC M0;
|
|
|
|
// If temperature is nonzero then allocate space for
|
|
// dynamical matrix and its derivative with respect to F.
|
|
if (finite_temp) {
|
|
D.reset(3,3);
|
|
dDdF.assign(6, DENS_MAT(3,3));
|
|
M0.assign(3, DENS_MAT(3,3));
|
|
L0.reset(3,3);
|
|
l0.reset(3);
|
|
}
|
|
|
|
if (F) *F = 0.0;
|
|
|
|
// if using EAM potential, calculate embedding function and derivatives
|
|
if (args.potential->terms.embedding) {
|
|
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
PairParam pair(args.vac.R(a), args.vac.bond_length(a));
|
|
e_density += args.potential->rho(pair.d);
|
|
pair.r = args.vac.r(a);
|
|
pair.rho_r = args.potential->rho_r(pair.d);
|
|
pair.rho_rr = args.potential->rho_rr(pair.d);
|
|
if (finite_temp) {
|
|
l0 += pair.r*pair.di*pair.rho_r;
|
|
DENS_MAT rR = tensor_product(pair.r, pair.R);
|
|
L0.add_scaled(rR, pair.di*pair.rho_r);
|
|
DENS_MAT rr = tensor_product(pair.r, pair.r);
|
|
rr *= pair.di*pair.di*(pair.rho_rr - pair.di*pair.rho_r);
|
|
diagonal(rr) += pair.di*pair.rho_r;
|
|
for (int i = 0; i < 3; i++) {
|
|
for (int k = 0; k < 3; k++) {
|
|
for (int L = 0; L < 3; L++) {
|
|
M0[i](k,L) += rr(i,k)*args.vac.R(a)(L);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
embed = args.potential->F(e_density); // "F" in usual EAM symbology
|
|
embed_p = args.potential->F_p(e_density);
|
|
embed_pp = args.potential->F_pp(e_density);
|
|
embed_ppp = args.potential->F_ppp(e_density);
|
|
if (F) *F += embed;
|
|
if (finite_temp) {
|
|
const DENS_MAT ll = tensor_product(l0, l0);
|
|
D.add_scaled(ll, embed_pp);
|
|
const DENS_VEC llvec = to_voigt(ll);
|
|
for (int v = 0; v < 6; v++) {
|
|
dDdF[v].add_scaled(L0, embed_ppp*llvec(v));
|
|
}
|
|
dDdF[0].add_scaled(M0[0], 2*embed_pp*l0(0));
|
|
dDdF[1].add_scaled(M0[1], 2*embed_pp*l0(1));
|
|
dDdF[2].add_scaled(M0[2], 2*embed_pp*l0(2));
|
|
dDdF[3].add_scaled(M0[1], embed_pp*l0(2));
|
|
dDdF[3].add_scaled(M0[2], embed_pp*l0(1));
|
|
dDdF[4].add_scaled(M0[0], embed_pp*l0(2));
|
|
dDdF[4].add_scaled(M0[2], embed_pp*l0(0));
|
|
dDdF[5].add_scaled(M0[0], embed_pp*l0(1));
|
|
dDdF[5].add_scaled(M0[1], embed_pp*l0(0));
|
|
}
|
|
}
|
|
|
|
// Loop on all cluster atoms (origin atom not included).
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
PairParam pair(args.vac.R(a), args.vac.bond_length(a));
|
|
if (args.potential->terms.pairwise) {
|
|
if (F) *F += 0.5*args.potential->phi(pair.d);
|
|
pair.phi_r = args.potential->phi_r(pair.d);
|
|
pairwise_stress(pair, s);
|
|
}
|
|
if (args.potential->terms.embedding) {
|
|
pair.F_p = embed_p;
|
|
pair.rho_r = args.potential->rho_r(pair.d);
|
|
embedding_stress(pair, s);
|
|
}
|
|
|
|
if (finite_temp) { // Compute finite T terms.
|
|
pair.r = args.vac.r(a);
|
|
if (args.potential->terms.pairwise) {
|
|
pair.phi_rr = args.potential->phi_rr(pair.d);
|
|
pair.phi_rrr = args.potential->phi_rrr(pair.d);
|
|
pairwise_thermal(pair, D, &dDdF);
|
|
}
|
|
if (args.potential->terms.embedding) {
|
|
pair.rho_rr = args.potential->rho_rr(pair.d);
|
|
pair.rho_rrr = args.potential->rho_rrr(pair.d);
|
|
pair.F_pp = embed_pp;
|
|
pair.F_ppp = embed_ppp;
|
|
embedding_thermal(pair,D,L0,&dDdF);
|
|
}
|
|
}
|
|
// if has three-body terms ... TODO compute three-body terms
|
|
}
|
|
|
|
// Finish finite temperature Cauchy-Born.
|
|
if (finite_temp) {
|
|
const DENS_MAT &F = args.vac.deformation_gradient();
|
|
thermal_end(dDdF, D, F, T, args.boltzmann_constant, s);
|
|
}
|
|
}
|
|
//===========================================================================
|
|
// Computes the elastic energy (free or potential if T=0).
|
|
//===========================================================================
|
|
double cb_energy(const StressArgs &args)
|
|
{
|
|
const double &T = args.temperature;
|
|
bool finite_temp = (T > 0.0);
|
|
//const bool finite_temp = T > 0.0;
|
|
DENS_MAT D; // dynamical matrix (finite temp)
|
|
double e_density,embed,embed_p(0.),embed_pp(0.),embed_ppp(0.);
|
|
DENS_VEC l0;
|
|
DENS_MAT L0;
|
|
DENS_MAT_VEC M0;
|
|
|
|
// If temperature is nonzero then allocate space for dynamical matrix.
|
|
if (finite_temp) {
|
|
D.reset(3,3);
|
|
l0.reset(3);
|
|
}
|
|
|
|
double F = 0.0;
|
|
// Do pairwise terms, loop on all cluster atoms (origin atom not included).
|
|
// if using EAM potential, calculate embedding function and derivatives
|
|
if (args.potential->terms.embedding) {
|
|
e_density = 0.0;
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
PairParam pair(args.vac.R(a), args.vac.bond_length(a));
|
|
e_density += args.potential->rho(pair.d);
|
|
pair.r = args.vac.r(a);
|
|
if (finite_temp) {
|
|
l0 += pair.r*pair.di*pair.rho_r;
|
|
}
|
|
}
|
|
embed = args.potential->F(e_density);
|
|
embed_p = args.potential->F_p(e_density);
|
|
embed_pp = args.potential->F_pp(e_density);
|
|
embed_ppp = args.potential->F_ppp(e_density);
|
|
F += embed;
|
|
if (finite_temp) {
|
|
const DENS_MAT ll = tensor_product(l0, l0);
|
|
D.add_scaled(ll, embed_pp);
|
|
}
|
|
}
|
|
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
PairParam pair(args.vac.R(a), args.vac.bond_length(a));
|
|
if (args.potential->terms.pairwise) {
|
|
F += 0.5*args.potential->phi(pair.d);
|
|
}
|
|
|
|
if (finite_temp) { // Compute finite T terms.
|
|
pair.r = args.vac.r(a);
|
|
if (args.potential->terms.pairwise) {
|
|
pair.phi_r = args.potential->phi_r(pair.d);
|
|
pair.phi_rr = args.potential->phi_rr(pair.d);
|
|
pair.phi_rrr = args.potential->phi_rrr(pair.d);
|
|
pairwise_thermal(pair, D);
|
|
}
|
|
if (args.potential->terms.embedding) {
|
|
pair.rho_r = args.potential->rho_r(pair.d);
|
|
pair.rho_rr = args.potential->rho_rr(pair.d);
|
|
pair.rho_rrr = args.potential->rho_rrr(pair.d);
|
|
pair.F_p = embed_p;
|
|
pair.F_pp = embed_pp;
|
|
pair.F_ppp = embed_ppp;
|
|
embedding_thermal(pair,D,L0);
|
|
}
|
|
}
|
|
// if has three-body terms ... TODO compute three-body terms
|
|
}
|
|
// Finish finite temperature Cauchy-Born.
|
|
const double kB = args.boltzmann_constant;
|
|
const double hbar = args.planck_constant;
|
|
if (finite_temp) {
|
|
F += kB*T*log(pow(hbar/(kB*T),3.0)*sqrt(det(D)));
|
|
}
|
|
//if (finite_temp) F += 0.5*args.boltzmann_constant*T*log(det(D));
|
|
return F;
|
|
}
|
|
//===========================================================================
|
|
// Computes the entropic energy TS (minus c_v T)
|
|
//===========================================================================
|
|
double cb_entropic_energy(const StressArgs &args)
|
|
{
|
|
const double &T = args.temperature;
|
|
DENS_MAT D(3,3); // dynamical matrix (finite temp)
|
|
double e_density,embed_p(0.),embed_pp(0.),embed_ppp(0.);
|
|
DENS_VEC l0(3);
|
|
DENS_MAT L0;
|
|
DENS_MAT_VEC M0;
|
|
|
|
// if using EAM potential, calculate embedding function and derivatives
|
|
if (args.potential->terms.embedding) {
|
|
e_density = 0.0;
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
PairParam pair(args.vac.R(a), args.vac.bond_length(a));
|
|
e_density += args.potential->rho(pair.d);
|
|
pair.r = args.vac.r(a);
|
|
l0 += pair.r*pair.di*pair.rho_r;
|
|
//DENS_MAT rR = tensor_product(pair.r, pair.R);
|
|
//L0.add_scaled(rR, pair.di*args.potential->rho_r(pair.d));
|
|
}
|
|
//embed = args.potential->F(e_density);
|
|
embed_p = args.potential->F_p(e_density);
|
|
embed_pp = args.potential->F_pp(e_density);
|
|
embed_ppp = args.potential->F_ppp(e_density);
|
|
const DENS_MAT ll = tensor_product(l0, l0);
|
|
D.add_scaled(ll, embed_pp);
|
|
}
|
|
|
|
// Compute the dynamical matrix
|
|
// Loop on all cluster atoms (origin atom not included).
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
// Compute pairwise terms needed for pairwise_stress.
|
|
PairParam pair(args.vac.R(a), args.vac.bond_length(a));
|
|
pair.r = args.vac.r(a);
|
|
if (args.potential->terms.pairwise) {
|
|
pair.phi_r = args.potential->phi_r(pair.d);
|
|
pair.phi_rr = args.potential->phi_rr(pair.d);
|
|
pair.phi_rrr = args.potential->phi_rrr(pair.d);
|
|
pairwise_thermal(pair, D);
|
|
}
|
|
if (args.potential->terms.embedding) {
|
|
pair.rho_r = args.potential->rho_r(pair.d);
|
|
pair.rho_rr = args.potential->rho_rr(pair.d);
|
|
pair.rho_rrr = args.potential->rho_rrr(pair.d);
|
|
pair.F_p = embed_p;
|
|
pair.F_pp = embed_pp;
|
|
pair.F_ppp = embed_ppp;
|
|
embedding_thermal(pair,D,L0);
|
|
}
|
|
}
|
|
// Finish finite temperature Cauchy-Born.
|
|
const double kB = args.boltzmann_constant;
|
|
const double hbar = args.planck_constant;;
|
|
double F = kB*T*log(pow(hbar/(kB*T),3.0)*sqrt(det(D)));
|
|
return F;
|
|
}
|
|
//===========================================================================
|
|
// Computes the stress contribution given the pairwise parameters.
|
|
//===========================================================================
|
|
inline void pairwise_stress(const PairParam &p, StressAtIP &s)
|
|
{
|
|
for (INDEX i=0; i<p.R.size(); i++)
|
|
for (INDEX j=i; j<p.R.size(); j++)
|
|
s(i,j) += 0.5*p.di * p.phi_r * p.R(i) * p.R(j);
|
|
}
|
|
|
|
//===========================================================================
|
|
// Computes the stress contribution given the embedding parameters.
|
|
//===========================================================================
|
|
inline void embedding_stress(const PairParam &p, StressAtIP &s)
|
|
{
|
|
for (INDEX i=0; i<p.R.size(); i++)
|
|
for (INDEX j=i; j<p.R.size(); j++)
|
|
s(i,j) += p.di * p.F_p * p.rho_r * p.R(i) * p.R(j);
|
|
}
|
|
|
|
//===========================================================================
|
|
// Computes the pairwise thermal components for the stress
|
|
//===========================================================================
|
|
void pairwise_thermal(const PairParam &p, DENS_MAT &D, DENS_MAT_VEC *dDdF)
|
|
{
|
|
const double di2 = p.di*p.di;
|
|
const double g = p.di*p.phi_r;
|
|
const double g_d = p.di*p.phi_rr - p.di*g; // units (energy / length^3)
|
|
const double f = di2 * (p.phi_rr - g); // units (energy / length^4)
|
|
const double f_d = di2*(p.phi_rrr-g_d) - 2.0*p.di*f;
|
|
|
|
// compute needed tensor products of r and R
|
|
const DENS_MAT rr = tensor_product(p.r, p.r);
|
|
|
|
// compute the dynamical matrix
|
|
D.add_scaled(rr, f);
|
|
diagonal(D) += g;
|
|
|
|
if (!dDdF) return; // skip derivative
|
|
const double gp_r = g_d*p.di;
|
|
const double fp_r = f_d*p.di;
|
|
const double fr[] = {f*p.r(0), f*p.r(1), f*p.r(2)};
|
|
const DENS_MAT rR = tensor_product(p.r, p.R);
|
|
|
|
DENS_MAT_VEC &dD = *dDdF;
|
|
|
|
// compute first term in A.13
|
|
dD[0].add_scaled(rR, fp_r*rr(0,0) + gp_r);
|
|
dD[1].add_scaled(rR, fp_r*rr(1,1) + gp_r);
|
|
dD[2].add_scaled(rR, fp_r*rr(2,2) + gp_r);
|
|
dD[3].add_scaled(rR, fp_r*rr(1,2));
|
|
dD[4].add_scaled(rR, fp_r*rr(0,2));
|
|
dD[5].add_scaled(rR, fp_r*rr(0,1));
|
|
|
|
// compute second term in A.13
|
|
for (INDEX L=0; L<p.R.size(); L++) {
|
|
dD[0](0,L) += p.R[L] * 2.0*fr[0];
|
|
dD[1](1,L) += p.R[L] * 2.0*fr[1];
|
|
dD[2](2,L) += p.R[L] * 2.0*fr[2];
|
|
dD[3](1,L) += p.R[L] * fr[2];
|
|
dD[3](2,L) += p.R[L] * fr[1];
|
|
dD[4](0,L) += p.R[L] * fr[2];
|
|
dD[4](2,L) += p.R[L] * fr[0];
|
|
dD[5](0,L) += p.R[L] * fr[1];
|
|
dD[5](1,L) += p.R[L] * fr[0];
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
// Computes the embedding thermal components for the stress
|
|
//===========================================================================
|
|
void embedding_thermal(const PairParam &p, DENS_MAT &D, DENS_MAT &L0, DENS_MAT_VEC *dDdF)
|
|
{
|
|
const double di = p.di;
|
|
const double di2 = p.di*p.di;
|
|
const double di3 = p.di*p.di*p.di;
|
|
const double x = p.F_pp*p.rho_r*p.rho_r + 2*p.F_p*p.rho_rr;
|
|
const double z = di*(2*p.F_p*p.rho_r);
|
|
const double y = di2*(x-z);
|
|
|
|
// compute needed tensor products of r and R
|
|
const DENS_MAT rr = tensor_product(p.r, p.r);
|
|
|
|
// compute the dynamical matrix
|
|
D.add_scaled(rr, y);
|
|
diagonal(D) += z;
|
|
|
|
if (!dDdF) return; // skip derivative
|
|
DENS_MAT_VEC &dD = *dDdF;
|
|
const DENS_MAT rR = tensor_product(p.r, p.R);
|
|
double rho_term1 = p.rho_rr - di*p.rho_r;
|
|
double rho_term2 = p.rho_r*rho_term1;
|
|
double rho_term3 = p.rho_rrr - 3*di*p.rho_rr + 3*di2*p.rho_r;
|
|
const double a = di2*2*p.F_p*rho_term1;
|
|
const double b = di2*(p.F_ppp*p.rho_r*p.rho_r + 2*p.F_pp*rho_term1);
|
|
const double c = di3*(2*p.F_pp*rho_term2 + 2*p.F_p*rho_term3);
|
|
const double w = di2*p.F_pp*p.rho_r*p.rho_r;
|
|
|
|
//first add terms that multiply rR
|
|
dD[0].add_scaled(rR, a + c*rr(0,0));
|
|
dD[1].add_scaled(rR, a + c*rr(1,1));
|
|
dD[2].add_scaled(rR, a + c*rr(2,2));
|
|
dD[3].add_scaled(rR, c*rr(1,2));
|
|
dD[4].add_scaled(rR, c*rr(0,2));
|
|
dD[5].add_scaled(rR, c*rr(0,1));
|
|
|
|
//add terms that multiply L0
|
|
dD[0].add_scaled(L0, di*2*p.F_pp*p.rho_r + b*rr(0,0));
|
|
dD[1].add_scaled(L0, di*2*p.F_pp*p.rho_r + b*rr(1,1));
|
|
dD[2].add_scaled(L0, di*2*p.F_pp*p.rho_r + b*rr(2,2));
|
|
dD[3].add_scaled(L0, b*rr(1,2));
|
|
dD[4].add_scaled(L0, b*rr(0,2));
|
|
dD[5].add_scaled(L0, b*rr(0,1));
|
|
|
|
//add remaining term
|
|
const double aw = a + w;
|
|
const double awr[] = {aw*p.r(0), aw*p.r(1), aw*p.r(2)};
|
|
for (INDEX L=0; L<p.R.size(); L++) {
|
|
dD[0](0,L) += 2*awr[0]*p.R[L];
|
|
dD[1](1,L) += 2*awr[1]*p.R[L];
|
|
dD[2](2,L) += 2*awr[2]*p.R[L];
|
|
dD[3](2,L) += awr[1]*p.R[L];
|
|
dD[3](1,L) += awr[2]*p.R[L];
|
|
dD[4](2,L) += awr[0]*p.R[L];
|
|
dD[4](0,L) += awr[2]*p.R[L];
|
|
dD[5](1,L) += awr[0]*p.R[L];
|
|
dD[5](0,L) += awr[1]*p.R[L];
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
// Last stage of the pairwise finite-T Cauchy-Born stress computation.
|
|
//===========================================================================
|
|
inline void thermal_end(const DENS_MAT_VEC &DF, // dynamical matrix derivative
|
|
const DENS_MAT &D, // dynamical matrix
|
|
const DENS_MAT &F, // deformation gradient
|
|
const double &T, // temperature
|
|
const double &kb, // boltzmann constant
|
|
StressAtIP &s, // output stress (-)
|
|
double* F_w) // output free energy (optional)
|
|
{
|
|
DENS_MAT c = adjugate(D), dd(3,3);
|
|
dd.add_scaled(DF[0], c(0,0));
|
|
dd.add_scaled(DF[1], c(1,1));
|
|
dd.add_scaled(DF[2], c(2,2));
|
|
dd.add_scaled(DF[3], c(1,2) + c(2,1));
|
|
dd.add_scaled(DF[4], c(0,2) + c(2,0));
|
|
dd.add_scaled(DF[5], c(0,1) + c(1,0));
|
|
|
|
const double detD = det(D);
|
|
const double factor = 0.5*kb*T/detD;
|
|
// converts from PK1 to PK2
|
|
dd = inv(F)*dd;
|
|
for (INDEX i=0; i<3; i++)
|
|
for (INDEX j=i; j<3; j++)
|
|
s(i,j) += factor * dd(i,j);
|
|
|
|
// If f_W is not NULL then append thermal contribution.
|
|
if (F_w) *F_w += 0.5*kb*T*log(detD);
|
|
}
|
|
//============================================================================
|
|
// Returns the stretch tensor and its derivative with respect to C (R C-G).
|
|
//============================================================================
|
|
void stretch_tensor_derivative(const DENS_VEC &C, DENS_VEC &U, DENS_MAT &dU)
|
|
{
|
|
// Compute the invariants of C
|
|
const DENS_VEC C2(voigt3::dsymm(C,C));
|
|
const double Ic = voigt3::tr(C);
|
|
const double IIc = 0.5*(Ic*Ic - voigt3::tr(C2));
|
|
const double IIIc = voigt3::det(C);
|
|
const DENS_VEC I = voigt3::eye(3);
|
|
|
|
// Compute the derivatives of the invarants of C
|
|
DENS_VEC dIc ( I );
|
|
DENS_VEC dIIc ( Ic*dIc - C );
|
|
DENS_VEC dIIIc ( voigt3::inv(C) * IIIc );
|
|
for (INDEX i=3; i<6; i++) {
|
|
dIIc(i) *= 2.0;
|
|
dIIIc(i) *= 2.0;
|
|
}
|
|
|
|
// Check if C is an isotropic tensor (simple case)
|
|
const double k = Ic*Ic - 3.0*IIc;
|
|
const DENS_VEC dk (2.0*Ic*dIc - 3.0*dIIc);
|
|
if (k < 1e-8) {
|
|
const double lambda = sqrt((1.0/3.0)*Ic);
|
|
const double dlambda = 0.5/(3.0*lambda);
|
|
U = I*lambda;
|
|
dU = tensor_product(dIc*dlambda, dIc); // may not be correct
|
|
return;
|
|
}
|
|
|
|
// Find the largest eigenvalue of C
|
|
const double L = Ic*(Ic*Ic - 4.5*IIc) + 13.5*IIIc;
|
|
DENS_VEC dL( (3.0*Ic*Ic-4.5*IIc)*dIc );
|
|
dL.add_scaled(dIIc, -4.5*Ic);
|
|
dL.add_scaled(dIIIc, 13.5);
|
|
const double kpow = pow(k,-1.5);
|
|
const double dkpow = -1.5*kpow/k;
|
|
const double phi = acos(L*kpow); // phi - good
|
|
|
|
// temporary factors for dphi
|
|
const double d1 = -1.0/sqrt(1.0-L*L*kpow*kpow);
|
|
const double d2 = d1*kpow;
|
|
const double d3 = d1*L*dkpow;
|
|
const DENS_VEC dphi (d2*dL + d3*dk);
|
|
|
|
const double sqrt_k=sqrt(k), cos_p3i=cos((1.0/3.0)*phi);
|
|
const double lam2 = (1.0/3.0)*(Ic + 2.0*sqrt_k*cos_p3i);
|
|
|
|
DENS_VEC dlam2 = (1.0/3.0)*dIc;
|
|
dlam2.add_scaled(dk, (1.0/3.0)*cos_p3i/sqrt_k);
|
|
dlam2.add_scaled(dphi, (-2.0/9.0)*sqrt_k*sin((1.0/3.0)*phi));
|
|
const double lambda = sqrt(lam2);
|
|
const DENS_VEC dlambda = (0.5/lambda)*dlam2;
|
|
|
|
// Compute the invariants of U
|
|
const double IIIu = sqrt(IIIc);
|
|
const DENS_VEC dIIIu (0.5/IIIu*dIIIc);
|
|
|
|
const double Iu = lambda + sqrt(-lam2 + Ic + 2.0*IIIu/lambda);
|
|
const double invrt = 1.0/(Iu-lambda);
|
|
DENS_VEC dIu(dlambda); dIu *= 1.0 + invrt*(-lambda - IIIu/lam2);
|
|
dIu.add_scaled(dIc, 0.5*invrt);
|
|
dIu.add_scaled(dIIIu, invrt/lambda);
|
|
|
|
const double IIu = 0.5*(Iu*Iu - Ic);
|
|
const DENS_VEC dIIu ( Iu*dIu - 0.5*dIc );
|
|
|
|
// Compute U and its derivatives
|
|
const double fct = 1.0/(Iu*IIu-IIIu);
|
|
DENS_VEC dfct = dIu; dfct *= IIu;
|
|
dfct.add_scaled(dIIu, Iu);
|
|
dfct -= dIIIu;
|
|
dfct *= -fct*fct;
|
|
|
|
U = voigt3::eye(3, Iu*IIIu);
|
|
U.add_scaled(C, Iu*Iu-IIu);
|
|
U -= C2;
|
|
|
|
DENS_MAT da = tensor_product(I, dIu); da *= IIIu;
|
|
da.add_scaled(tensor_product(I, dIIIu), Iu);
|
|
da += tensor_product(C, 2.0*Iu*dIu-dIIu);
|
|
da.add_scaled(eye<double>(6,6),Iu*Iu-IIu);
|
|
da -= voigt3::derivative_of_square(C);
|
|
|
|
dU = tensor_product(U, dfct);
|
|
dU.add_scaled(da, fct);
|
|
U *= fct;
|
|
}
|
|
//============================================================================
|
|
// Computes the dynamical matrix (TESTING FUNCTION)
|
|
//============================================================================
|
|
DENS_MAT compute_dynamical_matrix(const StressArgs &args)
|
|
{
|
|
DENS_MAT D(3,3);
|
|
for (INDEX a=0; a<args.vac.size(); a++) {
|
|
PairParam pair(args.vac.R(a), args.vac.r(a).norm());
|
|
pair.phi_r = args.potential->phi_r(pair.d);
|
|
pair.r = args.vac.r(a);
|
|
pair.phi_rr = args.potential->phi_rr(pair.d);
|
|
pair.phi_rrr = args.potential->phi_rrr(pair.d);
|
|
pairwise_thermal(pair, D);
|
|
}
|
|
return D;
|
|
}
|
|
//============================================================================
|
|
// Computes the determinant of the dynamical matrix (TESTING FUNCTION)
|
|
//============================================================================
|
|
double compute_detD(const StressArgs &args)
|
|
{
|
|
return det(compute_dynamical_matrix(args));
|
|
}
|
|
//============================================================================
|
|
// Computes the derivative of the dynamical matrix (TESTING FUNCTION)
|
|
//============================================================================
|
|
DENS_MAT_VEC compute_dynamical_derivative(StressArgs &args)
|
|
{
|
|
const double EPS = 1.0e-6;
|
|
DENS_MAT_VEC dDdF(6, DENS_MAT(3,3));
|
|
for (INDEX i=0; i<3; i++) {
|
|
for (INDEX j=0; j<3; j++) {
|
|
// store original F
|
|
const double Fij = args.vac.F_(i,j);
|
|
args.vac.F_(i,j) = Fij + EPS;
|
|
DENS_MAT Da = compute_dynamical_matrix(args);
|
|
args.vac.F_(i,j) = Fij - EPS;
|
|
DENS_MAT Db = compute_dynamical_matrix(args);
|
|
args.vac.F_(i,j) = Fij;
|
|
|
|
dDdF[0](i,j) = (Da(0,0)-Db(0,0))*(0.5/EPS);
|
|
dDdF[1](i,j) = (Da(1,1)-Db(1,1))*(0.5/EPS);
|
|
dDdF[2](i,j) = (Da(2,2)-Db(2,2))*(0.5/EPS);
|
|
dDdF[3](i,j) = (Da(1,2)-Db(1,2))*(0.5/EPS);
|
|
dDdF[4](i,j) = (Da(0,2)-Db(0,2))*(0.5/EPS);
|
|
dDdF[5](i,j) = (Da(0,1)-Db(0,1))*(0.5/EPS);
|
|
}
|
|
}
|
|
return dDdF;
|
|
}
|
|
}
|