#include "ATC_Transfer.h"
#include "ATC_Error.h"
#include "FE_Engine.h"
#include "LammpsInterface.h"
#include "Quadrature.h"
#include "VoigtOperations.h"
#include "TransferLibrary.h"
#include "Stress.h"
#include "KernelFunction.h"
#include "PerPairQuantity.h"
#include "FieldManager.h"
#define ESHELBY_VIRIAL
#include "LinearSolver.h"
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <fstream>
#include <sstream>
#include <exception>
using namespace std;
using namespace ATC_Utility;
using namespace voigt3;
namespace ATC {
const int numFields_ = 17;
FieldName indices_[numFields_] = {
CHARGE_DENSITY,
MASS_DENSITY,
SPECIES_CONCENTRATION,
NUMBER_DENSITY,
MOMENTUM,
VELOCITY,
PROJECTED_VELOCITY,
DISPLACEMENT,
POTENTIAL_ENERGY,
KINETIC_ENERGY,
KINETIC_TEMPERATURE,
TEMPERATURE,
CHARGE_FLUX,
SPECIES_FLUX,
THERMAL_ENERGY,
ENERGY,
INTERNAL_ENERGY
};
ATC_Transfer::ATC_Transfer(string groupName,
double ** & perAtomArray,
LAMMPS_NS::Fix * thisFix,
string matParamFile)
: ATC_Method(groupName,perAtomArray,thisFix),
xPointer_(NULL),
outputStepZero_(true),
neighborReset_(false),
pairMap_(NULL),
bondMatrix_(NULL),
pairVirial_(NULL),
pairHeatFlux_(NULL),
nComputes_(0),
hasPairs_(true),
hasBonds_(false),
resetKernelFunction_(false),
dxaExactMode_(true),
cauchyBornStress_(NULL)
{
nTypes_ = lammpsInterface_->ntypes();
peScale_=1.;
keScale_= lammpsInterface_->mvv2e();
if (matParamFile != "none") {
fstream fileId(matParamFile.c_str(), std::ios::in);
if (!fileId.is_open()) throw ATC_Error("cannot open material file");
CbData cb;
LammpsInterface *lmp = LammpsInterface::instance();
lmp->lattice(cb.cell_vectors, cb.basis_vectors);
cb.inv_atom_volume = 1.0 / lmp->volume_per_atom();
cb.e2mvv = 1.0 / lmp->mvv2e();
cb.atom_mass = lmp->atom_mass(1);
cb.boltzmann = lmp->boltz();
cb.hbar = lmp->hbar();
cauchyBornStress_ = new StressCauchyBorn(fileId, cb);
}
set_time();
outputFlags_.reset(NUM_TOTAL_FIELDS);
outputFlags_ = false;
fieldFlags_.reset(NUM_TOTAL_FIELDS);
fieldFlags_ = false;
gradFlags_.reset(NUM_TOTAL_FIELDS);
gradFlags_ = false;
rateFlags_.reset(NUM_TOTAL_FIELDS);
rateFlags_ = false;
outputFields_.resize(NUM_TOTAL_FIELDS);
for (int i = 0; i < NUM_TOTAL_FIELDS; i++) { outputFields_[i] = NULL; }
}
ATC_Transfer::~ATC_Transfer()
{
interscaleManager_.clear();
if (cauchyBornStress_) delete cauchyBornStress_;
}
void ATC_Transfer::initialize()
{
if (kernelOnTheFly_ && !readRefPE_ && !setRefPEvalue_) {
if (setRefPE_) {
stringstream ss;
ss << "WARNING: Reference PE requested from atoms, but not yet implemented for on-the-fly, ignoring";
lammpsInterface_->print_msg_once(ss.str());
setRefPE_ = false;
}
}
ATC_Method::initialize();
if (!initialized_) {
if (cauchyBornStress_) cauchyBornStress_->initialize();
}
if (!initialized_ || ATC::LammpsInterface::instance()->atoms_sorted() || resetKernelFunction_) {
if (! kernelOnTheFly_) {
try{
if (!moleculeIds_.empty()) compute_kernel_matrix_molecule(); }
catch(bad_alloc&) {
ATC::LammpsInterface::instance()->print_msg("kernel will be computed on-the-fly");
kernelOnTheFly_ = true;
}
}
resetKernelFunction_ = false;
}
ghostManager_.initialize();
if ((! bondOnTheFly_)
&& ( ( fieldFlags_(STRESS)
|| fieldFlags_(ESHELBY_STRESS)
|| fieldFlags_(HEAT_FLUX) ) ) ) {
try {
compute_bond_matrix();
}
catch(bad_alloc&) {
ATC::LammpsInterface::instance()->print_msg("stress/heat_flux will be computed on-the-fly");
bondOnTheFly_ = true;
}
}
if (sampleFrequency_ == 0) sampleFrequency_ = outputFrequency_;
if (!initialized_) {
if (outputFrequency_ > 0) {
compute_fields();
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if(fieldFlags_(index)) {
string name = field_to_string((FieldName) index);
filteredData_[name] = hardyData_[name];
timeFilters_(index)->initialize(filteredData_[name].quantity());
}
if (rateFlags_(index)) {
string name = field_to_string((FieldName) index);
string rate_field = name + "_rate";
filteredData_[rate_field] = hardyData_[rate_field];
}
if (gradFlags_(index)) {
string name = field_to_string((FieldName) index);
string grad_field = name + "_gradient";
filteredData_[grad_field] = hardyData_[grad_field];
}
}
int index = NUM_TOTAL_FIELDS;
map <string,int>::const_iterator iter;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
filteredData_[tag] = hardyData_[tag];
timeFilters_(index)->initialize(filteredData_[tag].quantity());
#ifdef ESHELBY_VIRIAL
if (tag == "virial" && fieldFlags_(ESHELBY_STRESS)) {
filteredData_["eshelby_virial"] = hardyData_["eshelby_virial"];
}
#endif
index++;
}
output();
}
}
initialized_ = true;
lammpsInterface_->computes_addstep(lammpsInterface_->ntimestep()+sampleFrequency_);
update_peratom_output();
}
void ATC_Transfer::set_continuum_data()
{
ATC_Method::set_continuum_data();
if (!initialized_) {
nNodesGlobal_ = feEngine_->fe_mesh()->num_nodes();
}
}
void ATC_Transfer::construct_time_integration_data()
{
if (!initialized_) {
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (fieldFlags_(index)) {
int size = FieldSizes[index];
if (atomToElementMapType_ == EULERIAN) {
if (index == STRESS) size=6;
if (index == CAUCHY_BORN_STRESS) size=6;
}
if (size == 0) {
if (index == SPECIES_CONCENTRATION) size=typeList_.size()+groupList_.size();
}
string name = field_to_string((FieldName) index);
hardyData_ [name].reset(nNodes_,size);
filteredData_[name].reset(nNodes_,size);
}
}
map <string,int>::const_iterator iter;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
COMPUTE_POINTER cmpt = lammpsInterface_->compute_pointer(tag);
int ncols = lammpsInterface_->compute_ncols_peratom(cmpt);
hardyData_ [tag].reset(nNodes_,ncols);
filteredData_[tag].reset(nNodes_,ncols);
#ifdef ESHELBY_VIRIAL
if (tag == "virial" && fieldFlags_(ESHELBY_STRESS)) {
string esh = "eshelby_virial";
int size = FieldSizes[ESHELBY_STRESS];
hardyData_ [esh].reset(nNodes_,size);
filteredData_[esh].reset(nNodes_,size);
}
#endif
}
}
}
void ATC_Transfer::set_computational_geometry()
{
ATC_Method::set_computational_geometry();
}
void ATC_Transfer::construct_interpolant()
{
if (!(kernelOnTheFly_)) {
PerAtomShapeFunction * atomShapeFunctions = new PerAtomShapeFunction(this);
interscaleManager_.add_per_atom_sparse_matrix(atomShapeFunctions,"Interpolant");
shpFcn_ = atomShapeFunctions;
}
this->create_atom_volume();
if (kernelFunction_) {
if (kernelOnTheFly_) {
ConstantQuantity<double> * atomCount = new ConstantQuantity<double>(this,1.);
interscaleManager_.add_per_atom_quantity(atomCount,"AtomCount");
OnTheFlyKernelAccumulation * myWeights
= new OnTheFlyKernelAccumulation(this,
atomCount, kernelFunction_, atomCoarseGrainingPositions_);
interscaleManager_.add_dense_matrix(myWeights,
"KernelInverseWeights");
accumulantWeights_ = new OnTheFlyKernelWeights(myWeights);
}
else {
PerAtomKernelFunction * atomKernelFunctions = new PerAtomKernelFunction(this);
interscaleManager_.add_per_atom_sparse_matrix(atomKernelFunctions,
"Accumulant");
accumulant_ = atomKernelFunctions;
accumulantWeights_ = new AccumulantWeights(accumulant_);
}
accumulantInverseVolumes_ = new KernelInverseVolumes(this,kernelFunction_);
interscaleManager_.add_diagonal_matrix(accumulantInverseVolumes_,
"AccumulantInverseVolumes");
interscaleManager_.add_diagonal_matrix(accumulantWeights_,
"AccumulantWeights");
}
else {
if (kernelOnTheFly_) {
ConstantQuantity<double> * atomCount = new ConstantQuantity<double>(this,1.);
interscaleManager_.add_per_atom_quantity(atomCount,"AtomCount");
OnTheFlyMeshAccumulation * myWeights
= new OnTheFlyMeshAccumulation(this,
atomCount, atomCoarseGrainingPositions_);
interscaleManager_.add_dense_matrix(myWeights,
"KernelInverseWeights");
accumulantWeights_ = new OnTheFlyKernelWeights(myWeights);
} else {
accumulant_ = shpFcn_;
accumulantWeights_ = new AccumulantWeights(accumulant_);
interscaleManager_.add_diagonal_matrix(accumulantWeights_,
"AccumulantWeights");
}
}
if (gradFlags_.has_member(true)) {
NativeShapeFunctionGradient * gradientMatrix = new NativeShapeFunctionGradient(this);
interscaleManager_.add_vector_sparse_matrix(gradientMatrix,"GradientMatrix");
gradientMatrix_ = gradientMatrix;
}
}
void ATC_Transfer::construct_molecule_transfers()
{
if (!moleculeIds_.empty()) {
map<string,pair<MolSize,int> >::const_iterator molecule;
InterscaleManager & interscaleManager = this->interscale_manager(); PerAtomQuantity<double> * atomProcGhostCoarseGrainingPositions_ = interscaleManager.per_atom_quantity("AtomicProcGhostCoarseGrainingPositions");
FundamentalAtomQuantity * mass = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,PROC_GHOST);
molecule = moleculeIds_.begin();
int groupbit = (molecule->second).second;
smallMoleculeSet_ = new SmallMoleculeSet(this,groupbit);
smallMoleculeSet_->initialize(); interscaleManager_.add_small_molecule_set(smallMoleculeSet_,"MoleculeSet");
moleculeCentroid_ = new SmallMoleculeCentroid(this,mass,smallMoleculeSet_,atomProcGhostCoarseGrainingPositions_);
interscaleManager_.add_dense_matrix(moleculeCentroid_,"MoleculeCentroid");
AtomToSmallMoleculeTransfer<double> * moleculeMass =
new AtomToSmallMoleculeTransfer<double>(this,mass,smallMoleculeSet_);
interscaleManager_.add_dense_matrix(moleculeMass,"MoleculeMass");
FundamentalAtomQuantity * atomicCharge = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE,PROC_GHOST);
AtomToSmallMoleculeTransfer<double> * moleculeCharge =
new AtomToSmallMoleculeTransfer<double>(this,atomicCharge,smallMoleculeSet_);
interscaleManager_.add_dense_matrix(moleculeCharge,"MoleculeCharge");
dipoleMoment_ = new SmallMoleculeDipoleMoment(this,atomicCharge,smallMoleculeSet_,atomProcGhostCoarseGrainingPositions_,moleculeCentroid_);
interscaleManager_.add_dense_matrix(dipoleMoment_,"DipoleMoment");
quadrupoleMoment_ = new SmallMoleculeQuadrupoleMoment(this,atomicCharge,smallMoleculeSet_,atomProcGhostCoarseGrainingPositions_,moleculeCentroid_);
interscaleManager_.add_dense_matrix(quadrupoleMoment_,"QuadrupoleMoment");
}
}
void ATC_Transfer::construct_transfers()
{
set_xPointer();
ATC_Method::construct_transfers();
if (setRefPE_) {
if (!setRefPEvalue_ && !readRefPE_) {
FieldManager fmgr(this);
nodalRefPotentialEnergy_ = fmgr.nodal_atomic_field(REFERENCE_POTENTIAL_ENERGY);
}
else {
nodalRefPotentialEnergy_ = new DENS_MAN(nNodes_,1);
nodalRefPotentialEnergy_->set_memory_type(PERSISTENT);
interscaleManager_.add_dense_matrix(nodalRefPotentialEnergy_,
field_to_string(REFERENCE_POTENTIAL_ENERGY));
}
}
bool needsBondMatrix = (! bondOnTheFly_ ) &&
(fieldFlags_(STRESS)
|| fieldFlags_(ESHELBY_STRESS)
|| fieldFlags_(HEAT_FLUX));
if (needsBondMatrix) {
if (hasPairs_ && hasBonds_) {
pairMap_ = new PairMapBoth(lammpsInterface_,groupbit_);
}
else if (hasBonds_) {
pairMap_ = new PairMapBond(lammpsInterface_,groupbit_);
}
else if (hasPairs_) {
pairMap_ = new PairMapNeighbor(lammpsInterface_,groupbit_);
}
}
if (pairMap_) interscaleManager_.add_pair_map(pairMap_,"PairMap");
if ( fieldFlags_(STRESS) || fieldFlags_(ESHELBY_STRESS) || fieldFlags_(HEAT_FLUX) ) {
const FE_Mesh * fe_mesh = feEngine_->fe_mesh();
if (!kernelBased_) {
bondMatrix_ = new BondMatrixPartitionOfUnity(lammpsInterface_,*pairMap_,xPointer_,fe_mesh,accumulantInverseVolumes_);
}
else {
bondMatrix_ = new BondMatrixKernel(lammpsInterface_,*pairMap_,xPointer_,fe_mesh,kernelFunction_);
}
}
if (bondMatrix_) interscaleManager_.add_sparse_matrix(bondMatrix_,"BondMatrix");
if ( fieldFlags_(STRESS) || fieldFlags_(ESHELBY_STRESS) ) {
if (atomToElementMapType_ == LAGRANGIAN) {
pairVirial_ = new PairVirialLagrangian(lammpsInterface_,*pairMap_,xref_);
}
else if (atomToElementMapType_ == EULERIAN) {
pairVirial_ = new PairVirialEulerian(lammpsInterface_,*pairMap_);
}
else {
throw ATC_Error("no atom to element map specified");
}
}
if (pairVirial_) interscaleManager_.add_dense_matrix(pairVirial_,"PairVirial");
if ( fieldFlags_(HEAT_FLUX) ) {
if (atomToElementMapType_ == LAGRANGIAN) {
pairHeatFlux_ = new PairPotentialHeatFluxLagrangian(lammpsInterface_,*pairMap_,xref_);
}
else if (atomToElementMapType_ == EULERIAN) {
pairHeatFlux_ = new PairPotentialHeatFluxEulerian(lammpsInterface_,*pairMap_);
}
else {
throw ATC_Error("no atom to element map specified");
}
}
if (pairHeatFlux_) interscaleManager_.add_dense_matrix(pairHeatFlux_,"PairHeatFlux");
FieldManager fmgr(this);
for(int i=0; i < numFields_; ++i) {
FieldName index = indices_[i];
if (fieldFlags_(index)) {
outputFields_[index] = fmgr.nodal_atomic_field(index);
}
}
if (fieldFlags_(ELECTRIC_POTENTIAL)) {
PerAtomQuantity<double> * atomCharge = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE);
restrictedCharge_ = fmgr.restricted_atom_quantity(CHARGE_DENSITY,"default",atomCharge);
}
map <string,int>::const_iterator iter;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
ComputedAtomQuantity * c = new ComputedAtomQuantity(this, tag);
interscaleManager_.add_per_atom_quantity(c,tag);
int projection = iter->second;
DIAG_MAN * w = NULL;
if (projection == VOLUME_NORMALIZATION )
{ w = accumulantInverseVolumes_; }
else if (projection == NUMBER_NORMALIZATION )
{ w = accumulantWeights_; }
if (kernelFunction_ && kernelOnTheFly_) {
OnTheFlyKernelAccumulationNormalized * C = new OnTheFlyKernelAccumulationNormalized(this, c, kernelFunction_, atomCoarseGrainingPositions_, w);
interscaleManager_.add_dense_matrix(C,tag);
outputFieldsTagged_[tag] = C;
}
else {
AtfProjection * C = new AtfProjection(this, c, accumulant_, w);
interscaleManager_.add_dense_matrix(C,tag);
outputFieldsTagged_[tag] = C;
}
}
}
void ATC_Transfer::construct_methods()
{
ATC_Method::construct_methods();
if ((!initialized_) || timeFilterManager_.need_reset()) {
timeFilters_.reset(NUM_TOTAL_FIELDS+nComputes_);
sampleCounter_ = 0;
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (fieldFlags_(index)) {
string name = field_to_string((FieldName) index);
filteredData_[name] = 0.0;
timeFilters_(index) = timeFilterManager_.construct();
}
}
map <string,int>::const_iterator iter;
int index = NUM_TOTAL_FIELDS;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
filteredData_[tag] = 0.0;
timeFilters_(index) = timeFilterManager_.construct();
index++;
}
}
}
void ATC_Transfer::finish()
{
ATC_Method::finish();
}
bool ATC_Transfer::modify(int narg, char **arg)
{
bool match = false;
int argIdx = 0;
if (strcmp(arg[argIdx],"fields")==0) {
argIdx++;
if (strcmp(arg[argIdx],"all")==0) {
outputFlags_ = true;
match = true;
}
else if (strcmp(arg[argIdx],"none")==0) {
outputFlags_ = false;
match = true;
}
else if (strcmp(arg[argIdx],"add")==0) {
argIdx++;
for (int i = argIdx; i < narg; ++i) {
FieldName field_name = string_to_field(arg[i]);
outputFlags_(field_name) = true;
}
match = true;
}
else if (strcmp(arg[argIdx],"delete")==0) {
argIdx++;
for (int i = argIdx; i < narg; ++i) {
FieldName field_name = string_to_field(arg[i]);
outputFlags_(field_name) = false;
}
match = true;
}
check_field_dependencies();
if (fieldFlags_(DISPLACEMENT)) { trackDisplacement_ = true; }
}
else if (strcmp(arg[argIdx],"gradients")==0) {
argIdx++;
if (strcmp(arg[argIdx],"add")==0) {
argIdx++;
FieldName field_name;
for (int i = argIdx; i < narg; ++i) {
field_name = string_to_field(arg[i]);
gradFlags_(field_name) = true;
}
match = true;
}
else if (strcmp(arg[argIdx],"delete")==0) {
argIdx++;
FieldName field_name;
for (int i = argIdx; i < narg; ++i) {
field_name = string_to_field(arg[i]);
gradFlags_(field_name) = false;
}
match = true;
}
}
else if (strcmp(arg[argIdx],"rates")==0) {
argIdx++;
if (strcmp(arg[argIdx],"add")==0) {
argIdx++;
FieldName field_name;
for (int i = argIdx; i < narg; ++i) {
field_name = string_to_field(arg[i]);
rateFlags_(field_name) = true;
}
match = true;
}
else if (strcmp(arg[argIdx],"delete")==0) {
argIdx++;
FieldName field_name;
for (int i = argIdx; i < narg; ++i) {
field_name = string_to_field(arg[i]);
rateFlags_(field_name) = false;
}
match = true;
}
}
if (strcmp(arg[argIdx],"pair_interactions")==0) { argIdx++;
if (strcmp(arg[argIdx],"on")==0) { hasPairs_ = true; }
else { hasPairs_ = false;}
match = true;
}
if (strcmp(arg[argIdx],"bond_interactions")==0) { argIdx++;
if (strcmp(arg[argIdx],"on")==0) { hasBonds_ = true; }
else { hasBonds_ = false;}
match = true;
}
else if (strcmp(arg[argIdx],"computes")==0) {
argIdx++;
if (strcmp(arg[argIdx],"add")==0) {
argIdx++;
string tag(arg[argIdx++]);
int normalization = NO_NORMALIZATION;
if (narg > argIdx) {
if (strcmp(arg[argIdx],"volume")==0) {
normalization = VOLUME_NORMALIZATION;
}
else if (strcmp(arg[argIdx],"number")==0) {
normalization = NUMBER_NORMALIZATION;
}
else if (strcmp(arg[argIdx],"mass")==0) {
normalization = MASS_NORMALIZATION;
throw ATC_Error("mass normalized not implemented");
}
}
computes_[tag] = normalization;
nComputes_++;
match = true;
}
else if (strcmp(arg[argIdx],"delete")==0) {
argIdx++;
string tag(arg[argIdx]);
if (computes_.find(tag) != computes_.end()) {
computes_.erase(tag);
nComputes_--;
}
else {
throw ATC_Error(tag+" compute is not in list");
}
match = true;
}
}
else if (strcmp(arg[argIdx],"sample_frequency")==0) {
argIdx++;
int value = outputFrequency_; if (narg > 1) {
if (atoi(arg[argIdx]) > 0) value = atoi(arg[argIdx]);
}
sampleFrequency_ = value;
match = true;
}
if (!match) {
match = ATC_Method::modify(narg, arg);
}
return match;
}
void ATC_Transfer::pre_init_integrate()
{
ATC_Method::pre_init_integrate();
}
void ATC_Transfer::pre_final_integrate()
{
update_time();
if ( neighborReset_ && sample_now() ) {
if (! kernelOnTheFly_ ) {
if (!moleculeIds_.empty()) compute_kernel_matrix_molecule(); }
neighborReset_ = false;
}
}
void ATC_Transfer::post_final_integrate()
{
double dt = lammpsInterface_->dt();
if ( sample_now() ) {
bool needsBond = (! bondOnTheFly_ ) &&
(fieldFlags_(STRESS)
|| fieldFlags_(ESHELBY_STRESS)
|| fieldFlags_(HEAT_FLUX));
if ( needsBond ) {
if (pairMap_->need_reset()) {
compute_bond_matrix();
}
}
time_filter_pre (dt);
compute_fields();
time_filter_post(dt);
lammpsInterface_->computes_addstep(lammpsInterface_->ntimestep()+sampleFrequency_);
}
if ( output_now() && !outputStepZero_ ) output();
outputStepZero_ = false;
}
void ATC_Transfer::compute_bond_matrix(void)
{
bondMatrix_->reset();
}
void ATC_Transfer::compute_fields(void)
{
interscaleManager_.lammps_force_reset();
for(int i=0; i < numFields_; ++i) {
FieldName index = indices_[i];
if (fieldFlags_(index)) {
DENS_MAT & data(hardyData_[field_to_string(index)].set_quantity());
data = (outputFields_[index])->quantity();
}
}
if (fieldFlags_(STRESS))
compute_stress(hardyData_["stress"].set_quantity());
if (fieldFlags_(HEAT_FLUX))
compute_heatflux(hardyData_["heat_flux"].set_quantity());
if (fieldFlags_(DIPOLE_MOMENT))
compute_dipole_moment(hardyData_["dipole_moment"].set_quantity());
if (fieldFlags_(QUADRUPOLE_MOMENT))
compute_quadrupole_moment(hardyData_["quadrupole_moment"].set_quantity());
if (fieldFlags_(DISLOCATION_DENSITY))
compute_dislocation_density(hardyData_["dislocation_density"].set_quantity());
if (gradFlags_.has_member(true)) {
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (gradFlags_(index)) {
string field= field_to_string((FieldName) index);
string grad_field = field + "_gradient";
if (hardyData_.find(field) == hardyData_.end() ) {
throw ATC_Error("field " + field + " needs to be defined for gradient");
}
gradient_compute(hardyData_[field].quantity(), hardyData_[grad_field].set_quantity());
}
}
}
if (fieldFlags_(ESHELBY_STRESS)) {
{
compute_eshelby_stress(hardyData_["eshelby_stress"].set_quantity(),
hardyData_["internal_energy"].quantity(),
hardyData_["stress"].quantity(),
hardyData_["displacement_gradient"].quantity());
}
}
if (fieldFlags_(CAUCHY_BORN_ESHELBY_STRESS)) {
DENS_MAT & H = hardyData_["displacement_gradient"].set_quantity();
DENS_MAT E(H.nRows(),1);
ATOMIC_DATA::const_iterator tfield = hardyData_.find("temperature");
const DENS_MAT *temp = tfield==hardyData_.end() ? NULL : &((tfield->second).quantity());
cauchy_born_energy(H, E, temp);
compute_eshelby_stress(hardyData_["cauchy_born_eshelby_stress"].set_quantity(),
E,hardyData_["stress"].quantity(),
hardyData_["displacement_gradient"].quantity());
}
if (fieldFlags_(CAUCHY_BORN_STRESS)) {
ATOMIC_DATA::const_iterator tfield = hardyData_.find("temperature");
const DENS_MAT *temp = tfield==hardyData_.end() ? NULL : &((tfield->second).quantity());
cauchy_born_stress(hardyData_["displacement_gradient"].quantity(),
hardyData_["cauchy_born_stress"].set_quantity(), temp);
}
if (fieldFlags_(CAUCHY_BORN_ENERGY)) {
ATOMIC_DATA::const_iterator tfield = hardyData_.find("temperature");
const DENS_MAT *temp = tfield==hardyData_.end() ? NULL : &((tfield->second).quantity());
cauchy_born_energy(hardyData_["displacement_gradient"].quantity(),
hardyData_["cauchy_born_energy"].set_quantity(), temp);
}
if (fieldFlags_(TRANSFORMED_STRESS)) {
compute_transformed_stress(hardyData_["transformed_stress"].set_quantity(),
hardyData_["stress"].quantity(),
hardyData_["displacement_gradient"].quantity());
}
if (fieldFlags_(VACANCY_CONCENTRATION)) {
compute_vacancy_concentration(hardyData_["vacancy_concentration"].set_quantity(),
hardyData_["displacement_gradient"].quantity(),
hardyData_["number_density"].quantity());
}
if (fieldFlags_(ELECTRIC_POTENTIAL)) {
compute_electric_potential(
hardyData_[field_to_string(ELECTRIC_POTENTIAL)].set_quantity());
}
if (fieldFlags_(ROTATION) || fieldFlags_(STRETCH)) {
compute_polar_decomposition(hardyData_["rotation"].set_quantity(),
hardyData_["stretch"].set_quantity(),
hardyData_["displacement_gradient"].quantity());
}
if (fieldFlags_(CAUCHY_BORN_ELASTIC_DEFORMATION_GRADIENT)) {
compute_elastic_deformation_gradient2(hardyData_["elastic_deformation_gradient"].set_quantity(),
hardyData_["stress"].quantity(),
hardyData_["displacement_gradient"].quantity());
}
lammpsInterface_->computes_clearstep();
map <string,int>::const_iterator iter;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
COMPUTE_POINTER cmpt = lammpsInterface_->compute_pointer(tag);
int projection = iter->second;
int ncols = lammpsInterface_->compute_ncols_peratom(cmpt);;
DENS_MAT atomicData(nLocal_,ncols);
if (ncols == 1) {
double * atomData = lammpsInterface_->compute_vector_peratom(cmpt);
for (int i = 0; i < nLocal_; i++) {
int atomIdx = internalToAtom_(i);
atomicData(i,0) = atomData[atomIdx];
}
}
else {
double ** atomData = lammpsInterface_->compute_array_peratom(cmpt);
for (int i = 0; i < nLocal_; i++) {
int atomIdx = internalToAtom_(i);
for (int k = 0; k < ncols; k++) {
atomicData(i,k) = atomData[atomIdx][k];
}
}
}
if (projection == NO_NORMALIZATION) {
project(atomicData,hardyData_[tag].set_quantity());
}
else if (projection == VOLUME_NORMALIZATION) {
project_volume_normalized(atomicData,hardyData_[tag].set_quantity());
}
else if (projection == NUMBER_NORMALIZATION) {
project_count_normalized(atomicData,hardyData_[tag].set_quantity());
}
else if (projection == MASS_NORMALIZATION) {
throw ATC_Error("unimplemented normalization");
}
else {
throw ATC_Error("unimplemented normalization");
}
#ifdef ESHELBY_VIRIAL
if (tag == "virial" && fieldFlags_(ESHELBY_STRESS)) {
if (atomToElementMapType_ == LAGRANGIAN) {
DENS_MAT tmp = hardyData_[tag].quantity();
DENS_MAT & myData(hardyData_[tag].set_quantity());
myData.reset(nNodes_,FieldSizes[STRESS]);
DENS_MAT F(3,3),FT(3,3),FTINV(3,3),CAUCHY(3,3),PK1(3,3);
const DENS_MAT& H(hardyData_["displacement_gradient"].quantity());
for (int k = 0; k < nNodes_; k++ ) {
vector_to_symm_matrix(k,tmp,CAUCHY);
vector_to_matrix(k,H,F);
F(0,0) += 1.0; F(1,1) += 1.0; F(2,2) += 1.0;
FT = F.transpose();
FTINV = inv(FT);
PK1 = CAUCHY*FTINV;
matrix_to_vector(k,PK1,myData);
}
}
compute_eshelby_stress(hardyData_["eshelby_virial"].set_quantity(),
hardyData_["internal_energy"].quantity(),hardyData_[tag].quantity(),
hardyData_["displacement_gradient"].quantity());
}
#endif
}
}
void ATC_Transfer::time_filter_pre(double dt)
{
sampleCounter_++;
string name;
double delta_t = dt*sampleFrequency_;
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (fieldFlags_(index)) {
name = field_to_string((FieldName) index);
timeFilters_(index)->apply_pre_step1(filteredData_[name].set_quantity(),
hardyData_[name].quantity(), delta_t);
}
}
map <string,int>::const_iterator iter;
int index = NUM_TOTAL_FIELDS;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
timeFilters_(index)->apply_pre_step1(filteredData_[tag].set_quantity(),
hardyData_[tag].quantity(), delta_t);
index++;
}
}
void ATC_Transfer::time_filter_post(double dt)
{
sampleCounter_++;
string name;
double delta_t = dt*sampleFrequency_;
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (fieldFlags_(index)) {
name = field_to_string((FieldName) index);
timeFilters_(index)->apply_post_step2(filteredData_[name].set_quantity(),
hardyData_[name].quantity(), delta_t);
}
}
if (rateFlags_.has_member(true)) {
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (rateFlags_(index)) {
string field= field_to_string((FieldName) index);
string rate_field = field + "_rate";
timeFilters_(index)->rate(hardyData_[rate_field].set_quantity(),
filteredData_[field].quantity(),
hardyData_[field].quantity(), delta_t);
}
}
}
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (rateFlags_(index)) {
name = field_to_string((FieldName) index);
string rate_field = name + "_rate";
filteredData_[rate_field] = hardyData_[rate_field];
}
if (gradFlags_(index)) {
name = field_to_string((FieldName) index);
string grad_field = name + "_gradient";
filteredData_[grad_field] = hardyData_[grad_field];
}
}
map <string,int>::const_iterator iter;
int index = NUM_TOTAL_FIELDS;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
timeFilters_(index)->apply_post_step2(filteredData_[tag].set_quantity(),
hardyData_[tag].quantity(), delta_t);
#ifdef ESHELBY_VIRIAL
if (tag == "virial" && fieldFlags_(ESHELBY_STRESS)) {
filteredData_["eshelby_virial"] = hardyData_["eshelby_virial"];
}
#endif
index++;
}
}
void ATC_Transfer::output()
{
feEngine_->departition_mesh();
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (outputFlags_(index)) {
FieldName fName = (FieldName) index;
string name= field_to_string(fName);
fields_[fName] = filteredData_[name];
}
}
ATC_Method::output();
if (lammpsInterface_->comm_rank() == 0) {
OUTPUT_LIST output_data;
#ifdef REFERENCE_PE_OUTPUT
output_data["reference_potential_energy"] = nodalRefPotentialEnergy_->quantity();
#endif
for(int index=0; index < NUM_TOTAL_FIELDS; ++index) {
if (outputFlags_(index)) {
string name= field_to_string((FieldName) index);
output_data[name] = & ( filteredData_[name].set_quantity());
}
if (rateFlags_(index)) {
string name= field_to_string((FieldName) index);
string rate_name = name + "_rate";
output_data[rate_name] = & ( filteredData_[rate_name].set_quantity());
}
if (gradFlags_(index)) {
string name= field_to_string((FieldName) index);
string grad_name = name + "_gradient";
output_data[grad_name] = & ( filteredData_[grad_name].set_quantity());
}
}
map <string,int>::const_iterator iter;
for (iter = computes_.begin(); iter != computes_.end(); iter++) {
string tag = iter->first;
output_data[tag] = & ( filteredData_[tag].set_quantity());
#ifdef ESHELBY_VIRIAL
if (tag == "virial" && fieldFlags_(ESHELBY_STRESS)) {
output_data["eshelby_virial"] = & ( filteredData_["eshelby_virial"].set_quantity() );
}
#endif
}
DENS_MAT nodalInverseVolumes = CLON_VEC(accumulantInverseVolumes_->quantity());
output_data["NodalInverseVolumes"] = &nodalInverseVolumes;
feEngine_->write_data(output_index(), & output_data);
}
feEngine_->partition_mesh();
}
void ATC_Transfer::project(const DENS_MAT & atomData,
DENS_MAT & nodeData)
{
if (! kernelOnTheFly_ ) {
nodeData.reset(nNodes_,atomData.nCols(),true);
DENS_MAT workNodeArray(nodeData.nRows(),nodeData.nCols());
if (nLocal_>0) workNodeArray = (accumulant_->quantity()).transMat(atomData);
int count = nodeData.nRows()*nodeData.nCols();
lammpsInterface_->allsum(workNodeArray.ptr(),nodeData.ptr(),count);
}
else {
compute_projection(atomData,nodeData);
}
}
void ATC_Transfer::project_molecule(const DENS_MAT & molData,
DENS_MAT & nodeData)
{
if (! kernelOnTheFly_ ) {
nodeData.reset(nNodes_,molData.nCols(),true);
DENS_MAT workNodeArray(nodeData.nRows(),nodeData.nCols());
if (nLocal_>0) workNodeArray = (accumulantMol_->quantity()).transMat(molData);
int count = nodeData.nRows()*nodeData.nCols();
lammpsInterface_->allsum(workNodeArray.ptr(),nodeData.ptr(),count);
}
else {
compute_projection(molData,nodeData);
}
}
void ATC_Transfer::project_molecule_gradient(const DENS_MAT & molData,
DENS_MAT & nodeData)
{
if (! kernelOnTheFly_ ) {
nodeData.reset(nNodes_,molData.nCols(),true);
DENS_MAT workNodeArray(nodeData.nRows(),nodeData.nCols());
if (nLocal_>0) workNodeArray = (accumulantMolGrad_->quantity()).transMat(molData);
int count = nodeData.nRows()*nodeData.nCols();
lammpsInterface_->allsum(workNodeArray.ptr(),nodeData.ptr(),count);
}
else {
compute_projection(molData,nodeData);
}
}
void ATC_Transfer::project_count_normalized(const DENS_MAT & atomData,
DENS_MAT & nodeData)
{
DENS_MAT tmp;
project(atomData,tmp);
nodeData = (accumulantWeights_->quantity())*tmp;
}
void ATC_Transfer::project_volume_normalized(const DENS_MAT & atomData,
DENS_MAT & nodeData)
{
DENS_MAT tmp;
project(atomData,tmp);
nodeData = (accumulantInverseVolumes_->quantity())*tmp;
}
void ATC_Transfer::project_volume_normalized_molecule(const DENS_MAT & molData,
DENS_MAT & nodeData)
{
DENS_MAT tmp;
project_molecule(molData,tmp);
nodeData = (accumulantInverseVolumes_->quantity())*tmp;
}
void ATC_Transfer::project_volume_normalized_molecule_gradient(const DENS_MAT & molData,
DENS_MAT & nodeData)
{
DENS_MAT tmp;
project_molecule_gradient(molData,tmp);
nodeData = (accumulantInverseVolumes_->quantity())*tmp;
}
void ATC_Transfer::gradient_compute(const DENS_MAT & inNodeData,
DENS_MAT & outNodeData)
{
int nrows = inNodeData.nRows();
int ncols = inNodeData.nCols();
outNodeData.reset(nrows,ncols*nsd_);
int index = 0;
for (int n = 0; n < ncols; n++) { for (int m = 0; m < nsd_; m++) {
CLON_VEC inData(inNodeData,CLONE_COL,n);
CLON_VEC outData(outNodeData,CLONE_COL,index);
outData = (*((gradientMatrix_->quantity())[m]))*inData;
++index;
}
}
}
void ATC_Transfer::compute_force_matrix()
{
atomicForceMatrix_ = pairVirial_->quantity();
}
void ATC_Transfer::compute_heat_matrix()
{
atomicHeatMatrix_ = pairHeatFlux_->quantity();
}
void ATC_Transfer::set_xPointer()
{
xPointer_ = xref_;
if (atomToElementMapType_ == EULERIAN) {
xPointer_ = lammpsInterface_->xatom();
}
}
void ATC_Transfer::check_field_dependencies()
{
fieldFlags_ = outputFlags_;
if (fieldFlags_(TRANSFORMED_STRESS)) {
fieldFlags_(STRESS) = true;
fieldFlags_(DISPLACEMENT) = true;
}
if (fieldFlags_(ESHELBY_STRESS)) {
fieldFlags_(STRESS) = true;
fieldFlags_(INTERNAL_ENERGY) = true;
fieldFlags_(DISPLACEMENT) = true;
}
if (fieldFlags_(CAUCHY_BORN_STRESS)
|| fieldFlags_(CAUCHY_BORN_ENERGY)
|| fieldFlags_(CAUCHY_BORN_ESHELBY_STRESS)
|| fieldFlags_(CAUCHY_BORN_ELASTIC_DEFORMATION_GRADIENT)) {
if (! (cauchyBornStress_) ) {
throw ATC_Error("can't compute cauchy-born stress w/o cauchy born model");
}
}
if (fieldFlags_(CAUCHY_BORN_ELASTIC_DEFORMATION_GRADIENT)) {
fieldFlags_(STRESS) = true;
}
if (fieldFlags_(CAUCHY_BORN_STRESS)
|| fieldFlags_(CAUCHY_BORN_ENERGY)) {
fieldFlags_(TEMPERATURE) = true;
fieldFlags_(DISPLACEMENT) = true;
}
if (fieldFlags_(CAUCHY_BORN_ESHELBY_STRESS)) {
fieldFlags_(TEMPERATURE) = true;
fieldFlags_(DISPLACEMENT) = true;
fieldFlags_(STRESS) = true;
}
if (fieldFlags_(VACANCY_CONCENTRATION)) {
fieldFlags_(DISPLACEMENT) = true;
fieldFlags_(NUMBER_DENSITY) = true;
}
if (fieldFlags_(INTERNAL_ENERGY)) {
fieldFlags_(POTENTIAL_ENERGY) = true;
fieldFlags_(THERMAL_ENERGY) = true;
}
if (fieldFlags_(ENERGY)) {
fieldFlags_(POTENTIAL_ENERGY) = true;
fieldFlags_(KINETIC_ENERGY) = true;
}
if (fieldFlags_(TEMPERATURE) || fieldFlags_(HEAT_FLUX) ||
fieldFlags_(KINETIC_ENERGY) || fieldFlags_(THERMAL_ENERGY) ||
fieldFlags_(ENERGY) || fieldFlags_(INTERNAL_ENERGY) ||
fieldFlags_(KINETIC_ENERGY) || (fieldFlags_(STRESS) &&
atomToElementMapType_ == EULERIAN) ) {
fieldFlags_(VELOCITY) = true;
fieldFlags_(MASS_DENSITY) = true;
}
if (fieldFlags_(VELOCITY)) {
fieldFlags_(MASS_DENSITY) = true;
fieldFlags_(MOMENTUM) = true;
}
if (fieldFlags_(DISPLACEMENT)) {
fieldFlags_(MASS_DENSITY) = true;
}
if (fieldFlags_(TEMPERATURE) ) {
fieldFlags_(NUMBER_DENSITY) = true;
}
if (fieldFlags_(ROTATION) ||
fieldFlags_(STRETCH)) {
fieldFlags_(DISPLACEMENT) = true;
}
if (fieldFlags_(ESHELBY_STRESS)
|| fieldFlags_(CAUCHY_BORN_STRESS)
|| fieldFlags_(CAUCHY_BORN_ENERGY)
|| fieldFlags_(CAUCHY_BORN_ESHELBY_STRESS)
|| fieldFlags_(CAUCHY_BORN_ELASTIC_DEFORMATION_GRADIENT)
|| fieldFlags_(VACANCY_CONCENTRATION)
|| fieldFlags_(ROTATION)
|| fieldFlags_(STRETCH) ) {
gradFlags_(DISPLACEMENT) = true;
}
if (fieldFlags_(STRESS) || fieldFlags_(HEAT_FLUX)) {
if (lammpsInterface_->single_enable()==0) {
throw ATC_Error("Calculation of stress field not possible with selected pair type.");
}
}
}
void ATC_Transfer::compute_dipole_moment(DENS_MAT & dipole_moment)
{
const DENS_MAT & molecularVector(dipoleMoment_->quantity());
project_volume_normalized_molecule(molecularVector,dipole_moment); }
void ATC_Transfer::compute_quadrupole_moment(DENS_MAT & quadrupole_moment)
{
const DENS_MAT & molecularVector(quadrupoleMoment_->quantity());
project_volume_normalized_molecule_gradient(molecularVector,quadrupole_moment); }
void ATC_Transfer::compute_stress(DENS_MAT & stress)
{
double nktv2p = lammpsInterface_->nktv2p();
if (atomToElementMapType_ == EULERIAN && nLocal_>0) {
compute_kinetic_stress(stress);
}
else {
stress.zero();
}
int nrows = stress.nRows();
int ncols = stress.nCols();
DENS_MAT local_potential_hardy_stress(nrows,ncols);
if (nLocal_>0) {
if (bondOnTheFly_) {
compute_potential_stress(local_potential_hardy_stress);
}
else {
compute_force_matrix();
local_potential_hardy_stress = atomicBondMatrix_*atomicForceMatrix_;
local_potential_hardy_stress *= 0.5;
}
}
DENS_MAT potential_hardy_stress(nrows,ncols);
int count = nrows*ncols;
lammpsInterface_->allsum(local_potential_hardy_stress.ptr(),
potential_hardy_stress.ptr(), count);
stress += potential_hardy_stress;
stress = nktv2p*stress;
}
void ATC_Transfer::compute_kinetic_stress(DENS_MAT& stress)
{
const DENS_MAT& density = hardyData_["mass_density"].quantity();
const DENS_MAT& velocity = hardyData_["velocity"].quantity();
int * type = lammpsInterface_->atom_type();
double * mass = lammpsInterface_->atom_mass();
double * rmass = lammpsInterface_->atom_rmass();
double ** vatom = lammpsInterface_->vatom();
double mvv2e = lammpsInterface_->mvv2e();
atomicTensor_.reset(nLocal_,6);
for (int i = 0; i < nLocal_; i++) {
int atomIdx = internalToAtom_(i);
double ma = mass ? mass[type[atomIdx]]: rmass[atomIdx];
ma *= mvv2e; double* v = vatom[atomIdx];
atomicTensor_(i,0) -= ma*v[0]*v[0];
atomicTensor_(i,1) -= ma*v[1]*v[1];
atomicTensor_(i,2) -= ma*v[2]*v[2];
atomicTensor_(i,3) -= ma*v[0]*v[1];
atomicTensor_(i,4) -= ma*v[0]*v[2];
atomicTensor_(i,5) -= ma*v[1]*v[2];
}
project_volume_normalized(atomicTensor_, stress);
for (int i = 0; i < nNodes_; i++) {
double rho_i = mvv2e*density(i,0);
stress(i,0) += rho_i*velocity(i,0)*velocity(i,0);
stress(i,1) += rho_i*velocity(i,1)*velocity(i,1);
stress(i,2) += rho_i*velocity(i,2)*velocity(i,2);
stress(i,3) += rho_i*velocity(i,0)*velocity(i,1);
stress(i,4) += rho_i*velocity(i,0)*velocity(i,2);
stress(i,5) += rho_i*velocity(i,1)*velocity(i,2);
}
}
void ATC_Transfer::compute_heatflux(DENS_MAT & flux)
{
if (atomToElementMapType_ == EULERIAN && nLocal_>0) {
compute_kinetic_heatflux(flux);
}
else {
flux.zero(); }
int nrows = flux.nRows();
int ncols = flux.nCols();
DENS_MAT local_hardy_heat(nrows,ncols);
if (nLocal_>0) {
if (bondOnTheFly_) {
compute_potential_heatflux(local_hardy_heat);
}
else {
compute_heat_matrix();
local_hardy_heat = atomicBondMatrix_*atomicHeatMatrix_;
}
}
DENS_MAT hardy_heat(nrows,ncols);
int count = nrows*ncols;
lammpsInterface_->allsum(local_hardy_heat.ptr(),
hardy_heat.ptr(), count);
flux += hardy_heat;
}
void ATC_Transfer::compute_kinetic_heatflux(DENS_MAT& flux)
{
const DENS_MAT& velocity = hardyData_["velocity"].quantity();
const DENS_MAT& energy = hardyData_["mass_density"].quantity();
const DENS_MAT& stress = hardyData_["stress"].quantity();
int * type = lammpsInterface_->atom_type();
double * mass = lammpsInterface_->atom_mass();
double * rmass = lammpsInterface_->atom_rmass();
double ** vatom = lammpsInterface_->vatom();
double mvv2e = lammpsInterface_->mvv2e();
double * atomPE = lammpsInterface_->compute_pe_peratom();
double atomKE, atomEnergy;
atomicVector_.reset(nLocal_,3);
for (int i = 0; i < nLocal_; i++) {
int atomIdx = internalToAtom_(i);
double ma = mass ? mass[type[atomIdx]]: rmass[atomIdx];
ma *= mvv2e; double* v = vatom[atomIdx];
atomKE = 0.0;
for (int k = 0; k < nsd_; k++) { atomKE += v[k]*v[k]; }
atomKE *= 0.5*ma;
atomEnergy = atomKE + atomPE[atomIdx];
for (int j = 0; j < nsd_; j++) {
atomicVector_(i,j) += atomEnergy*v[j];
}
}
project_volume_normalized(atomicVector_,flux);
for (int i = 0; i < nNodes_; i++) {
double e_i = energy(i,0);
flux(i,0) += (e_i + stress(i,0))*velocity(i,0)
+ stress(i,3)*velocity(i,1)+ stress(i,4)*velocity(i,2);
flux(i,1) += (e_i + stress(i,1))*velocity(i,1)
+ stress(i,3)*velocity(i,0)+ stress(i,5)*velocity(i,2);
flux(i,2) += (e_i + stress(i,2))*velocity(i,2)
+ stress(i,4)*velocity(i,0)+ stress(i,5)*velocity(i,1);
}
}
void ATC_Transfer::compute_electric_potential(DENS_MAT & phi)
{
const DENS_MAT & rho = (restrictedCharge_->quantity());
SPAR_MAT K;
feEngine_->stiffness_matrix(K);
double permittivity = lammpsInterface_->dielectric();
permittivity *= LammpsInterface::instance()->epsilon0();
K *= permittivity;
BC_SET bcs;
bcs.insert(pair<int,int>(0,0));
LinearSolver solver(K,bcs);
CLON_VEC x = column(phi,0);
CLON_VEC b = column(rho,0);
solver.solve(x,b);
}
void ATC_Transfer::compute_vacancy_concentration(DENS_MAT & Cv,
const DENS_MAT & H, const DENS_MAT & rhoN)
{
int * type = lammpsInterface_->atom_type();
DENS_MAT new_rho(nNodes_,1);
DENS_MAT atomCnt(nLocal_,1);
double atomic_weight_sum = 0.0;
double site_weight_sum = 0.0;
int number_atoms = 0;
const DIAG_MAT & myAtomicWeights(atomVolume_->quantity());
for (int i = 0; i < nLocal_; i++) {
int atomIdx = internalToAtom_(i);
if (type[atomIdx] != 13) {
atomCnt(i,0) = myAtomicWeights(i,i);
atomic_weight_sum += myAtomicWeights(i,i);
number_atoms++;
}
site_weight_sum += myAtomicWeights(i,i);
}
project_volume_normalized(atomCnt, new_rho);
DENS_MAT F(3,3);
for (int i = 0; i < nNodes_; i++) {
if (atomToElementMapType_ == EULERIAN) {
DENS_MAT G(3,3);
vector_to_matrix(i,H,G);
G *= -1.;
G(0,0) += 1.0; G(1,1) += 1.0; G(2,2) += 1.0;
F = inv(G);
}
else if (atomToElementMapType_ == LAGRANGIAN) {
vector_to_matrix(i,H,F);
F(0,0) += 1.0; F(1,1) += 1.0; F(2,2) += 1.0;
}
double J = det(F);
double volume_per_atom = lammpsInterface_->volume_per_atom();
J *= volume_per_atom;
Cv(i,0) = 1.0 - J*new_rho(i,0);
}
}
void ATC_Transfer::compute_eshelby_stress(DENS_MAT & M,
const DENS_MAT & E, const DENS_MAT & S, const DENS_MAT & H)
{
M.reset(nNodes_,FieldSizes[ESHELBY_STRESS]);
double nktv2p = lammpsInterface_->nktv2p();
DENS_MAT P(3,3),F(3,3),FT(3,3),FTP(3,3),ESH(3,3);
for (int i = 0; i < nNodes_; i++) {
double W = E(i,0);
ESH.identity();
ESH *= W;
if (atomToElementMapType_ == LAGRANGIAN) {
vector_to_matrix(i,S,P);
vector_to_matrix(i,H,F);
#ifndef H_BASED
F(0,0) += 1.0; F(1,1) += 1.0; F(2,2) += 1.0;
#endif
FT = F.transpose();
}
else if (atomToElementMapType_ == EULERIAN) {
vector_to_symm_matrix(i,S,P);
vector_to_matrix(i,H,F);
FT = F.transpose();
}
FTP = (1.0/nktv2p)*FT*P;
ESH -= FTP;
if (atomToElementMapType_ == EULERIAN) {
DENS_MAT Q(3,3);
Q.identity();
Q -= FT.transpose();
DENS_MAT F(3,3);
F = inv(Q);
FT = F.transpose();
ESH = FT*ESH;
}
matrix_to_vector(i,ESH,M);
}
}
void ATC_Transfer::cauchy_born_stress(const DENS_MAT &H, DENS_MAT &T, const DENS_MAT *temp)
{
FIELD_MATS uField; DENS_MAT_VEC tField;
GRAD_FIELD_MATS hField;
DENS_MAT_VEC &h = hField[DISPLACEMENT];
h.assign(nsd_, DENS_MAT(nNodes_,nsd_));
tField.assign(nsd_, DENS_MAT(nNodes_,nsd_));
T.reset(nNodes_,FieldSizes[CAUCHY_BORN_STRESS]);
const double nktv2p = lammpsInterface_->nktv2p();
const double fact = -lammpsInterface_->mvv2e()*nktv2p;
vector_to_dens_mat_vec(H,h);
if (temp) uField[TEMPERATURE] = *temp;
cauchyBornStress_->stress(uField, hField, tField);
DENS_MAT S(nNodes_,6);
symm_dens_mat_vec_to_vector(tField,S);
S *= fact;
DENS_MAT PK2(3,3),G(3,3),F(3,3),FT(3,3),STRESS(3,3);
for (int i = 0; i < nNodes_; i++) {
vector_to_symm_matrix(i,S,PK2);
if (atomToElementMapType_ == EULERIAN) {
vector_to_matrix(i,H,G);
G *= -1.;
G(0,0) += 1.0; G(1,1) += 1.0; G(2,2) += 1.0;
F = inv(G);
FT = transpose(F);
double J = det(F);
STRESS = F*PK2*FT;
STRESS *= 1/J;
symm_matrix_to_vector(i,STRESS,T);
}
else{
vector_to_matrix(i,H,F);
F(0,0) += 1.0; F(1,1) += 1.0; F(2,2) += 1.0;
STRESS = F*PK2;
matrix_to_vector(i,STRESS,T);
}
}
}
void ATC_Transfer::cauchy_born_energy(const DENS_MAT &H, DENS_MAT &E, const DENS_MAT *temp)
{
FIELD_MATS uField; GRAD_FIELD_MATS hField;
DENS_MAT_VEC &h = hField[DISPLACEMENT];
h.assign(nsd_, DENS_MAT(nNodes_,nsd_));
vector_to_dens_mat_vec(H,h);
if (temp) uField[TEMPERATURE] = *temp;
cauchyBornStress_->elastic_energy(uField, hField, E);
double mvv2e = lammpsInterface_->mvv2e(); E *= mvv2e;
if (atomToElementMapType_ == EULERIAN) {
DENS_MAT G(3,3),F(3,3);
for (int i = 0; i < nNodes_; i++) {
vector_to_matrix(i,H,G);
G *= -1.;
G(0,0) += 1.0; G(1,1) += 1.0; G(2,2) += 1.0;
F = inv(G);
double J = det(F);
E(i,0) *= 1/J;
}
}
if (nodalRefPotentialEnergy_)
E -= nodalRefPotentialEnergy_->quantity();
}
void ATC_Transfer::cauchy_born_entropic_energy(const DENS_MAT &H, DENS_MAT &E, const DENS_MAT &T)
{
FIELD_MATS uField; uField[TEMPERATURE] = T;
GRAD_FIELD_MATS hField;
DENS_MAT_VEC &h = hField[DISPLACEMENT];
h.assign(nsd_, DENS_MAT(nNodes_,nsd_));
vector_to_dens_mat_vec(H,h);
cauchyBornStress_->entropic_energy(uField, hField, E);
double mvv2e = lammpsInterface_->mvv2e(); E *= mvv2e;
if (atomToElementMapType_ == EULERIAN) {
DENS_MAT G(3,3),F(3,3);
for (int i = 0; i < nNodes_; i++) {
vector_to_matrix(i,H,G);
G *= -1.;
G(0,0) += 1.0; G(1,1) += 1.0; G(2,2) += 1.0;
F = inv(G);
double J = det(F);
E(i,0) *= 1/J;
}
}
}
void ATC_Transfer::compute_transformed_stress(DENS_MAT & stress,
const DENS_MAT & T, const DENS_MAT & H)
{
stress.reset(nNodes_,FieldSizes[TRANSFORMED_STRESS]);
DENS_MAT S(3,3),FT(3,3),P(3,3);
for (int i = 0; i < nNodes_; i++) {
if (atomToElementMapType_ == EULERIAN) {
vector_to_symm_matrix(i,T,P);
DENS_MAT G(3,3);
vector_to_matrix(i,H,G);
G *= -1.;
G(0,0) += 1.0; G(1,1) += 1.0; G(2,2) += 1.0;
FT = inv(G.transpose());
}
else{
vector_to_matrix(i,T,P);
DENS_MAT F(3,3);
vector_to_matrix(i,H,F);
F(0,0) += 1.0; F(1,1) += 1.0; F(2,2) += 1.0;
FT = F.transpose();
}
double J = det(FT);
FT *= 1/J;
if (atomToElementMapType_ == EULERIAN) {
FT = inv(FT);
}
S = P*FT;
matrix_to_vector(i,S,stress);
}
}
void ATC_Transfer::compute_polar_decomposition(DENS_MAT & rotation,
DENS_MAT & stretch, const DENS_MAT & H)
{
DENS_MAT F(3,3),R(3,3),U(3,3);
for (int i = 0; i < nNodes_; i++) {
vector_to_matrix(i,H,F);
F(0,0) += 1.0; F(1,1) += 1.0; F(2,2) += 1.0;
if (atomToElementMapType_ == EULERIAN) {
polar_decomposition(F,R,U,false); } else {
polar_decomposition(F,R,U); } if ( fieldFlags_(ROTATION) ) {
matrix_to_vector(i,R,rotation);
}
if ( fieldFlags_(STRETCH) ) {
matrix_to_vector(i,U,stretch);
}
}
}
void ATC_Transfer::compute_elastic_deformation_gradient(DENS_MAT & Fe,
const DENS_MAT & P, const DENS_MAT & H)
{
const double nktv2p = lammpsInterface_->nktv2p();
const double fact = 1.0/ ( lammpsInterface_->mvv2e()*nktv2p );
for (int i = 0; i < nNodes_; i++) {
DENS_VEC Pv = global_vector_to_vector(i,P);
Pv *= fact;
CBElasticTangentOperator tangent(cauchyBornStress_, Pv);
NonLinearSolver solver(&tangent);
DENS_VEC Fv = global_vector_to_vector(i,H); add_identity_voigt_unsymmetric(Fv);
solver.solve(Fv);
vector_to_global_vector(i,Fv,Fe);
}
}
void ATC_Transfer::compute_elastic_deformation_gradient2(DENS_MAT & Fe,
const DENS_MAT & P, const DENS_MAT & H)
{
const double nktv2p = lammpsInterface_->nktv2p();
const double fact = 1.0/ ( lammpsInterface_->mvv2e()*nktv2p );
DENS_MAT F(3,3),R(3,3),U(3,3),PP(3,3),S(3,3);
for (int i = 0; i < nNodes_; i++) {
vector_to_matrix(i,H,F);
F(0,0) += 1.0; F(1,1) += 1.0; F(2,2) += 1.0;
if (atomToElementMapType_ == EULERIAN) {
polar_decomposition(F,R,U,false); } else {
polar_decomposition(F,R,U); } vector_to_matrix(i,P,PP);
S = inv(F)*PP;
S += S.transpose(); S *= 0.5; DENS_VEC Sv = to_voigt(S);
Sv *= fact;
CB2ndElasticTangentOperator tangent(cauchyBornStress_, Sv);
NonLinearSolver solver(&tangent);
DENS_VEC Uv = to_voigt(U); solver.solve(Uv);
DENS_MAT Ue = from_voigt(Uv);
DENS_MAT FFe = R*Ue;
matrix_to_vector(i,FFe,Fe);
}
}
}