forked from lijiext/lammps
1235 lines
45 KiB
C++
1235 lines
45 KiB
C++
// ATC_Transfer Headers
|
|
#include "ATC_Error.h"
|
|
#include "Kinetostat.h"
|
|
#include "CG.h"
|
|
#include "ATC_Transfer.h"
|
|
#include "LammpsInterface.h"
|
|
|
|
namespace ATC {
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class Kinetostat
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
//--------------------------------------------------------
|
|
Kinetostat::Kinetostat(ATC_Transfer * atcTransfer) :
|
|
AtomicRegulator(atcTransfer),
|
|
kinetostatType_(NONE),
|
|
couplingMode_(UNCOUPLED)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// modify:
|
|
// parses and adjusts kinetostat state based on
|
|
// user input, in the style of LAMMPS user input
|
|
//--------------------------------------------------------
|
|
bool Kinetostat::modify(int narg, char **arg)
|
|
{
|
|
bool foundMatch = false;
|
|
|
|
// fluxstat type
|
|
/*! \page man_disp_control fix_modify AtC transfer momentum control
|
|
\section syntax
|
|
fix_modify AtC transfer momentum control none \n
|
|
|
|
fix_modify AtC transfer momentum control rescale <frequency>\n
|
|
- frequency (int) = time step frequency for applying displacement and velocity rescaling \n
|
|
|
|
fix_modify AtC transfer momentum control glc_displacement \n
|
|
|
|
fix_modify AtC transfer momentum control glc_velocity \n
|
|
|
|
fix_modify AtC transfer momentum control flux [faceset face_set_id, interpolate]
|
|
- face_set_id (string) = id of boundary face set, if not specified
|
|
(or not possible when the atomic domain does not line up with
|
|
mesh boundaries) defaults to an atomic-quadrature approximate
|
|
evaulation\n
|
|
\section examples
|
|
fix_modify AtC transfer momentum control glc_velocity \n
|
|
fix_modify AtC transfer momentum control stress_flux faceset bndy_faces \n
|
|
\section description
|
|
\section restrictions
|
|
only for be used with specific transfers :
|
|
elastic \n
|
|
rescale not valid with time filtering activated
|
|
\section related
|
|
\section default
|
|
none
|
|
*/
|
|
|
|
int argIndex = 0;
|
|
if (strcmp(arg[argIndex],"none")==0) { // restore defaults
|
|
kinetostatType_ = NONE;
|
|
couplingMode_ = UNCOUPLED;
|
|
howOften_ = 1;
|
|
boundaryIntegrationType_ = ATC_Transfer::NO_QUADRATURE;
|
|
foundMatch = true;
|
|
}
|
|
else if (strcmp(arg[argIndex],"glc_displacement")==0) {
|
|
kinetostatType_ = GLC_DISPLACEMENT;
|
|
couplingMode_ = FIXED;
|
|
howOften_ = 1;
|
|
boundaryIntegrationType_ = ATC_Transfer::NO_QUADRATURE;
|
|
foundMatch = true;
|
|
}
|
|
else if (strcmp(arg[argIndex],"glc_velocity")==0) {
|
|
kinetostatType_ = GLC_VELOCITY;
|
|
couplingMode_ = FIXED;
|
|
howOften_ = 1;
|
|
boundaryIntegrationType_ = ATC_Transfer::NO_QUADRATURE;
|
|
foundMatch = true;
|
|
}
|
|
else if (strcmp(arg[argIndex],"hoover")==0) {
|
|
kinetostatType_ = FORCE;
|
|
couplingMode_ = FIXED;
|
|
howOften_ = 1;
|
|
boundaryIntegrationType_ = ATC_Transfer::NO_QUADRATURE;
|
|
foundMatch = true;
|
|
}
|
|
else if (strcmp(arg[argIndex],"flux")==0) {
|
|
kinetostatType_ = FORCE;
|
|
couplingMode_ = FLUX;
|
|
howOften_ = 1;
|
|
argIndex++;
|
|
boundaryIntegrationType_ = atcTransfer_->parse_boundary_integration(narg-argIndex,&arg[argIndex],boundaryFaceSet_);
|
|
foundMatch = true;
|
|
}
|
|
|
|
if (!foundMatch)
|
|
foundMatch = AtomicRegulator::modify(narg,arg);
|
|
if (foundMatch)
|
|
needReset_ = true;
|
|
return foundMatch;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// reset_nodal_lambda_force:
|
|
// resets the kinetostat generated force to a
|
|
// prescribed value
|
|
//--------------------------------------------------------
|
|
void Kinetostat::reset_lambda_force(DENS_MAT & target)
|
|
{
|
|
for (int i = 0; i < nNodes_; ++i)
|
|
for (int j = 0; j < nsd_; ++j)
|
|
lambdaForceFiltered_(i,j) = target(i,j);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// initialize:
|
|
// sets up methods before a run
|
|
// NOTE we currently only include time filter
|
|
// dependence, but in general there is also a
|
|
// time integrator dependence. In general the
|
|
// precedence order is:
|
|
// time filter -> time integrator -> kinetostat
|
|
// In the future this may need to be added if
|
|
// different types of time integrators can be
|
|
// specified.
|
|
//--------------------------------------------------------
|
|
void Kinetostat::initialize()
|
|
{
|
|
// NOTE: only support basic time integration
|
|
TimeFilterManager * timeFilterManager = atcTransfer_->get_time_filter_manager();
|
|
|
|
// reset data if needed and perform any error/conflict checking
|
|
if (resetData_) {
|
|
AtomicRegulator::reset_data();
|
|
|
|
// set up storage
|
|
lambda_.reset(nNodes_,nsd_);
|
|
nodalAtomicLambdaForce_.reset(nNodes_,nsd_);
|
|
lambdaForceFiltered_.reset(nNodes_,nsd_);
|
|
}
|
|
|
|
if (needReset_ || timeFilterManager->need_reset() || timeFilterManager->end_equilibrate()) {
|
|
// eliminate existing methods
|
|
destroy();
|
|
|
|
DENS_MAT nodalGhostForceFiltered;
|
|
if (timeFilterManager->end_equilibrate() && kinetostatType_==FORCE) {
|
|
StressFlux * myMethod;
|
|
myMethod = dynamic_cast<StressFlux *>(regulatorMethod_);
|
|
nodalGhostForceFiltered = myMethod->get_filtered_ghost_force();
|
|
}
|
|
|
|
if (timeFilterManager->need_reset()) {
|
|
if (timeFilter_)
|
|
delete timeFilter_;
|
|
timeFilter_ = timeFilterManager->construct(TimeFilterManager::IMPLICIT_UPDATE);
|
|
}
|
|
|
|
if (timeFilterManager->filter_dynamics()) {
|
|
switch (kinetostatType_) {
|
|
case NONE: {
|
|
break;
|
|
}
|
|
case GLC_DISPLACEMENT: {
|
|
regulatorMethod_ = new DisplacementGlcFiltered(this);
|
|
break;
|
|
}
|
|
case GLC_VELOCITY: {
|
|
regulatorMethod_ = new VelocityGlcFiltered(this);
|
|
break;
|
|
}
|
|
case FORCE: {
|
|
regulatorMethod_ = new StressFluxFiltered(this);
|
|
if (timeFilterManager->end_equilibrate()) {
|
|
StressFlux * myMethod;
|
|
myMethod = dynamic_cast<StressFlux *>(regulatorMethod_);
|
|
myMethod->reset_filtered_ghost_force(nodalGhostForceFiltered);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
throw ATC_Error(0,"Unknown kinetostat type in Kinetostat::initialize");
|
|
}
|
|
}
|
|
else {
|
|
switch (kinetostatType_) {
|
|
case NONE: {
|
|
break;
|
|
}
|
|
case GLC_DISPLACEMENT: {
|
|
regulatorMethod_ = new DisplacementGlc(this);
|
|
break;
|
|
}
|
|
case GLC_VELOCITY: {
|
|
regulatorMethod_ = new VelocityGlc(this);
|
|
break;
|
|
}
|
|
case FORCE: {
|
|
regulatorMethod_ = new StressFlux(this);
|
|
break;
|
|
}
|
|
default:
|
|
throw ATC_Error(0,"Unknown kinetostat type in Kinetostat::initialize");
|
|
}
|
|
}
|
|
|
|
AtomicRegulator::reset_method();
|
|
}
|
|
|
|
AtomicRegulator::initialize();
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class GlcKinetostat
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
// Grab references to ATC and kinetostat data
|
|
//--------------------------------------------------------
|
|
GlcKinetostat::GlcKinetostat(Kinetostat *kinetostat)
|
|
:
|
|
RegulatorShapeFunction(kinetostat),
|
|
kinetostat_(kinetostat),
|
|
timeFilter_(atomicRegulator_->get_time_filter()),
|
|
nodalAtomicLambdaForce_(kinetostat_->get_nodal_atomic_lambda_force()),
|
|
lambdaForceFiltered_(kinetostat_->get_lambda_force_filtered()),
|
|
lambdaForce_(atomicRegulator_->get_lambda_force()),
|
|
mdMassMatrix_(atcTransfer_->get_mass_mat_md(VELOCITY)),
|
|
nodeToOverlapMap_(atcTransfer_->get_node_to_overlap_map())
|
|
{
|
|
// set up list of nodes using Hoover coupling
|
|
// (a) nodes with prescribed values
|
|
Array2D<bool> isFixedNode = atcTransfer_->get_fixed_node_flags(VELOCITY);
|
|
for (int i = 0; i < nNodes_; ++i)
|
|
for (int j = 0; j < isFixedNode.nCols(); ++j)
|
|
if (isFixedNode(i,j))
|
|
hooverNodes_.insert(pair<int,int>(i,j));
|
|
|
|
// (b) AtC coupling nodes
|
|
if (kinetostat_->get_coupling_mode()==Kinetostat::FIXED) {
|
|
Array<int> & nodeType(atcTransfer_->get_node_type());
|
|
if (atcTransfer_->use_localized_lambda()) {
|
|
for (int i = 0; i < nNodes_; ++i)
|
|
if (nodeType(i)==ATC_Transfer::BOUNDARY)
|
|
for (int j = 0; j < nsd_; ++j)
|
|
hooverNodes_.insert(pair<int,int>(i,j));
|
|
}
|
|
else {
|
|
for (int i = 0; i < nNodes_; ++i)
|
|
if (nodeType(i)==ATC_Transfer::BOUNDARY || nodeType(i)==ATC_Transfer::MD_ONLY)
|
|
for (int j = 0; j < nsd_; ++j)
|
|
hooverNodes_.insert(pair<int,int>(i,j));
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_lambda_to_atoms
|
|
// uses existing lambda to modify given
|
|
// atomic quantity
|
|
//--------------------------------------------------------
|
|
void GlcKinetostat::apply_to_atoms(double ** atomicQuantity,
|
|
const DENS_MAT & lambdaAtom,
|
|
double dt)
|
|
{
|
|
if (nLocal_>0) {
|
|
for (int i = 0; i < nLocal_; i++) {
|
|
for (int j = 0; j < nsd_; j++) {
|
|
atomicQuantity[internalToAtom_(i)][j] -= lambdaAtom(i,j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_weights
|
|
// sets diagonal weighting matrix used in
|
|
// solve_for_lambda
|
|
//--------------------------------------------------------
|
|
void GlcKinetostat::set_weights(DIAG_MAT & weights)
|
|
{
|
|
if (nLocalLambda_>0) {
|
|
DENS_VEC weightVector(nLocal_);
|
|
weightVector = 1.;
|
|
DENS_VEC maskedWeightVector(nLocalLambda_);
|
|
maskedWeightVector = internalToOverlapMap_*weightVector;
|
|
weights.reset(maskedWeightVector);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// reset_nlocal:
|
|
// resets data dependent on local atom count
|
|
//--------------------------------------------------------
|
|
void GlcKinetostat::reset_nlocal()
|
|
{
|
|
RegulatorShapeFunction::reset_nlocal();
|
|
if (nLocal_ > 0) {
|
|
atcTransfer_->compute_atomic_mass(atomicMass_);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class DisplacementGlc
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
// Grab references to ATC and kinetostat data
|
|
//--------------------------------------------------------
|
|
DisplacementGlc::DisplacementGlc(Kinetostat * kinetostat) :
|
|
GlcKinetostat(kinetostat),
|
|
nodalDisplacements_(atcTransfer_->get_field(DISPLACEMENT)),
|
|
x_(atcTransfer_->get_x())
|
|
{
|
|
// sets up time filter for cases where variables temporally filtered
|
|
TimeFilterManager * timeFilterManager = atcTransfer_->get_time_filter_manager();
|
|
if (!timeFilterManager->end_equilibrate()) {
|
|
nodalAtomicLambdaForce_ = 0.;
|
|
lambdaForceFiltered_ = 0.;
|
|
timeFilter_->initialize(lambdaForceFiltered_);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply:
|
|
// apply the kinetostat to the atoms
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::apply_post_predictor(double dt)
|
|
{
|
|
compute_kinetostat(dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_kinetostat
|
|
// manages the solution and application of the
|
|
// kinetostat equations and variables
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::compute_kinetostat(double dt)
|
|
{
|
|
// initial filtering update
|
|
apply_pre_filtering(dt);
|
|
|
|
// set up rhs
|
|
DENS_MAT rhs(nNodes_,nsd_);
|
|
set_kinetostat_rhs(rhs,dt);
|
|
|
|
// solve linear system for lambda
|
|
solve_for_lambda(rhs);
|
|
|
|
// compute force applied by lambda
|
|
DENS_MAT lambdaAtom;
|
|
compute_lambda_force(lambdaForce_,lambdaAtom,dt);
|
|
|
|
// compute nodal atomic power
|
|
compute_nodal_lambda_force(dt);
|
|
|
|
// apply kinetostat to atoms
|
|
apply_to_atoms(x_,lambdaAtom);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_kinetostat_rhs
|
|
// sets up the right-hand side of the
|
|
// kinetostat equations
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
|
|
{
|
|
// form rhs : sum_a (hatN_Ia * x_ai) - (Upsilon)_Ii
|
|
DENS_MAT atomicDisplacement;
|
|
atcTransfer_->compute_atomic_centerOfMass_displacement(atomicDisplacement,x_);
|
|
rhs.reset(nNodes_,nsd_);
|
|
atcTransfer_->restrict_volumetric_quantity(atomicDisplacement,rhs);
|
|
rhs -= (atcTransfer_->get_mass_mat_md(VELOCITY))*nodalDisplacements_;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_lambda_force
|
|
// compute the equivalent force on the atoms
|
|
// induced by lambda
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::compute_lambda_force(DENS_MAT & lambdaForce,
|
|
DENS_MAT & lambdaAtom,
|
|
double dt)
|
|
{
|
|
if (nLocal_>0) {
|
|
// prolongation to (unique) nodes
|
|
lambdaAtom.reset(nLocal_,nsd_);
|
|
atcTransfer_->prolong(lambda_,lambdaAtom);
|
|
|
|
for (int i = 0; i < nLocal_; i++)
|
|
for (int j = 0; j < nsd_; j++)
|
|
lambdaForce(i,j) = (-1./(dt*dt))*lambdaAtom(i,j)*atomicMass_(i);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_nodal_lambda_force
|
|
// compute the effective FE force applied
|
|
// by the kinetostat
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::compute_nodal_lambda_force(double dt)
|
|
{
|
|
atcTransfer_->restrict_volumetric_quantity(lambdaForce_,nodalAtomicLambdaForce_);
|
|
timeFilter_->apply_post_step1(lambdaForceFiltered_,nodalAtomicLambdaForce_,dt);
|
|
|
|
// update FE displacements for localized thermostats
|
|
apply_localization_correction(nodalAtomicLambdaForce_,
|
|
nodalDisplacements_,
|
|
dt*dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_pre_filtering
|
|
// applies first step of filtering to
|
|
// relevant variables
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::apply_pre_filtering(double dt)
|
|
{
|
|
// apply time filtered lambda force
|
|
DENS_MAT lambdaZero(nNodes_,nsd_);
|
|
timeFilter_->apply_pre_step1(lambdaForceFiltered_,(-1./dt/dt)*lambdaZero,dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_weights
|
|
// sets diagonal weighting matrix used in
|
|
// solve_for_lambda
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::set_weights(DIAG_MAT & weights)
|
|
{
|
|
if (nLocalLambda_>0) {
|
|
DENS_VEC maskedWeightVector(nLocalLambda_);
|
|
maskedWeightVector = internalToOverlapMap_*atomicMass_;
|
|
weights.reset(maskedWeightVector);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_localization_correction
|
|
// corrects for localized kinetostats only
|
|
// solving kinetostat equations on a subset
|
|
// of the MD region
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::apply_localization_correction(const DENS_MAT & source,
|
|
DENS_MAT & nodalField,
|
|
double weight)
|
|
{
|
|
// NOTE can add check to see if set is empty for faster performance
|
|
DENS_MAT nodalLambdaRoc(nNodes_,nsd_);
|
|
atcTransfer_->apply_inverse_mass_matrix(source,
|
|
nodalLambdaRoc,
|
|
VELOCITY);
|
|
set<pair<int,int> >::const_iterator iter;
|
|
for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
|
|
nodalLambdaRoc(iter->first,iter->second) = 0.;
|
|
}
|
|
|
|
nodalField += weight*nodalLambdaRoc;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// output:
|
|
// adds all relevant output to outputData
|
|
//--------------------------------------------------------
|
|
void DisplacementGlc::output(double dt, OUTPUT_LIST & outputData)
|
|
{
|
|
outputData["lambda"] = &(lambda_);
|
|
outputData["nodalLambdaForce"] = &(nodalAtomicLambdaForce_);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class DisplacementGlcFiltered
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
// Grab references to ATC and kinetostat data
|
|
//--------------------------------------------------------
|
|
DisplacementGlcFiltered::DisplacementGlcFiltered(Kinetostat * kinetostat) :
|
|
DisplacementGlc(kinetostat),
|
|
nodalAtomicDisplacements_(atcTransfer_->get_atomic_field(DISPLACEMENT))
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_pre_filtering
|
|
// applies first step of filtering to
|
|
// relevant variables
|
|
//--------------------------------------------------------
|
|
void DisplacementGlcFiltered::apply_pre_filtering(double dt)
|
|
{
|
|
// apply time filtered lambda to atomic fields
|
|
DisplacementGlc::apply_pre_filtering(dt);
|
|
DENS_MAT nodalAcceleration(nNodes_,nsd_);
|
|
atcTransfer_->apply_inverse_md_mass_matrix(lambdaForceFiltered_,
|
|
nodalAcceleration,
|
|
VELOCITY);
|
|
nodalAtomicDisplacements_ += dt*dt*nodalAcceleration;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_kinetostat_rhs
|
|
// sets up the right-hand side of the
|
|
// kinetostat equations
|
|
//--------------------------------------------------------
|
|
void DisplacementGlcFiltered::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
|
|
{
|
|
// form rhs : sum_a (hatN_Ia * x_ai) - (Upsilon)_Ii
|
|
double coef = 1./(timeFilter_->get_unfiltered_coefficient_pre_s1(dt));
|
|
rhs = coef*(atcTransfer_->get_mass_mat_md(VELOCITY))*(nodalAtomicDisplacements_ - nodalDisplacements_);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_nodal_lambda_force
|
|
// compute the effective FE force applied
|
|
// by the kinetostat
|
|
//--------------------------------------------------------
|
|
void DisplacementGlcFiltered::compute_nodal_lambda_force(double dt)
|
|
{
|
|
atcTransfer_->restrict_volumetric_quantity(lambdaForce_,nodalAtomicLambdaForce_);
|
|
timeFilter_->apply_post_step1(lambdaForceFiltered_,nodalAtomicLambdaForce_,dt);
|
|
|
|
// update filtered atomic displacements
|
|
DENS_MAT nodalLambdaRoc(nodalAtomicLambdaForce_.nRows(),nodalAtomicLambdaForce_.nCols());
|
|
atcTransfer_->apply_inverse_md_mass_matrix(nodalAtomicLambdaForce_,
|
|
nodalLambdaRoc,
|
|
VELOCITY);
|
|
timeFilter_->apply_post_step1(nodalAtomicDisplacements_,dt*dt*nodalLambdaRoc,dt);
|
|
|
|
// update FE displacements for localized thermostats
|
|
apply_localization_correction(lambdaForceFiltered_,
|
|
nodalDisplacements_,
|
|
dt*dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// output:
|
|
// adds all relevant output to outputData
|
|
//--------------------------------------------------------
|
|
void DisplacementGlcFiltered::output(double dt, OUTPUT_LIST & outputData)
|
|
{
|
|
outputData["lambda"] = &(lambda_);
|
|
outputData["nodalLambdaForce"] = &(lambdaForceFiltered_);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class VelocityGlc
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
// Grab references to ATC and kinetostat data
|
|
//--------------------------------------------------------
|
|
VelocityGlc::VelocityGlc(Kinetostat * kinetostat) :
|
|
GlcKinetostat(kinetostat),
|
|
nodalVelocities_(atcTransfer_->get_field(VELOCITY)),
|
|
v_(atcTransfer_->get_v())
|
|
{
|
|
// sets up time filter for cases where variables temporally filtered
|
|
TimeFilterManager * timeFilterManager = atcTransfer_->get_time_filter_manager();
|
|
if (!timeFilterManager->end_equilibrate()) {
|
|
nodalAtomicLambdaForce_ = 0.;
|
|
lambdaForceFiltered_ = 0.;
|
|
timeFilter_->initialize(lambdaForceFiltered_);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_mid_corrector:
|
|
// apply the kinetostat during the middle of the
|
|
// predictor phase
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::apply_mid_predictor(double dt)
|
|
{
|
|
double dtLambda = 0.5*dt;
|
|
compute_kinetostat(dtLambda);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_post_corrector:
|
|
// apply the kinetostat after the corrector phase
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::apply_post_corrector(double dt)
|
|
{
|
|
double dtLambda = 0.5*dt;
|
|
compute_kinetostat(dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_pre_filtering
|
|
// applies first step of filtering to
|
|
// relevant variables
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::apply_pre_filtering(double dt)
|
|
{
|
|
// apply time filtered lambda to atomic fields
|
|
DENS_MAT lambdaZero(nNodes_,nsd_);
|
|
timeFilter_->apply_pre_step1(lambdaForceFiltered_,(-1./dt)*lambdaZero,dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_kinetostat
|
|
// manages the solution and application of the
|
|
// kinetostat equations and variables
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::compute_kinetostat(double dt)
|
|
{
|
|
// initial filtering update
|
|
apply_pre_filtering(dt);
|
|
|
|
// set up rhs
|
|
DENS_MAT rhs(nNodes_,nsd_);
|
|
set_kinetostat_rhs(rhs,dt);
|
|
|
|
// solve linear system for lambda
|
|
solve_for_lambda(rhs);
|
|
|
|
// compute force applied by lambda
|
|
DENS_MAT lambdaAtom;
|
|
compute_lambda_force(lambdaForce_,lambdaAtom,dt);
|
|
|
|
// compute nodal atomic power
|
|
compute_nodal_lambda_force(dt);
|
|
|
|
// apply kinetostat to atoms
|
|
apply_to_atoms(v_,lambdaAtom);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_kinetostat_rhs
|
|
// sets up the right-hand side of the
|
|
// kinetostat equations
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
|
|
{
|
|
// form rhs : sum_a (hatN_Ia * x_ai) - (\dot{Upsilon})_Ii
|
|
DENS_MAT atomicMomentum;
|
|
atcTransfer_->compute_atomic_momentum(atomicMomentum,v_);
|
|
rhs.reset(nNodes_,nsd_);
|
|
atcTransfer_->restrict_volumetric_quantity(atomicMomentum,rhs);
|
|
rhs -= (atcTransfer_->get_mass_mat_md(VELOCITY))*nodalVelocities_;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_lambda_force
|
|
// compute the equivalent force on the atoms
|
|
// induced by lambda
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::compute_lambda_force(DENS_MAT & lambdaForce,
|
|
DENS_MAT & lambdaAtom,
|
|
double dt)
|
|
{
|
|
if (nLocal_>0) {
|
|
// prolongation to (unique) nodes
|
|
lambdaAtom.reset(nLocal_,nsd_);
|
|
atcTransfer_->prolong(lambda_,lambdaAtom);
|
|
|
|
for (int i = 0; i < nLocal_; i++)
|
|
for (int j = 0; j < nsd_; j++)
|
|
lambdaForce(i,j) = (-1./(dt))*lambdaAtom(i,j)*atomicMass_(i);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_nodal_lambda_force
|
|
// compute the effective FE force applied
|
|
// by the kinetostat
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::compute_nodal_lambda_force(double dt)
|
|
{
|
|
atcTransfer_->restrict_volumetric_quantity(lambdaForce_,nodalAtomicLambdaForce_);
|
|
timeFilter_->apply_pre_step1(lambdaForceFiltered_,nodalAtomicLambdaForce_,dt);
|
|
|
|
// update FE displacements for localized thermostats
|
|
apply_localization_correction(nodalAtomicLambdaForce_,
|
|
nodalVelocities_,
|
|
dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_weights
|
|
// sets diagonal weighting matrix used in
|
|
// solve_for_lambda
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::set_weights(DIAG_MAT & weights)
|
|
{
|
|
if (nLocalLambda_>0) {
|
|
DENS_VEC maskedWeightVector = internalToOverlapMap_*atomicMass_;
|
|
weights.reset(maskedWeightVector);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_localization_correction
|
|
// corrects for localized kinetostats only
|
|
// solving kinetostat equations on a subset
|
|
// of the MD region
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::apply_localization_correction(const DENS_MAT & source,
|
|
DENS_MAT & nodalField,
|
|
double weight)
|
|
{
|
|
// NOTE can add check to see if set is empty for faster performance
|
|
DENS_MAT nodalLambdaRoc(nNodes_,nsd_);
|
|
atcTransfer_->apply_inverse_mass_matrix(source,
|
|
nodalLambdaRoc,
|
|
VELOCITY);
|
|
set<pair<int,int> >::const_iterator iter;
|
|
for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
|
|
nodalLambdaRoc(iter->first,iter->second) = 0.;
|
|
}
|
|
|
|
nodalField += weight*nodalLambdaRoc;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// output:
|
|
// adds all relevant output to outputData
|
|
//--------------------------------------------------------
|
|
void VelocityGlc::output(double dt, OUTPUT_LIST & outputData)
|
|
{
|
|
outputData["lambda"] = &(lambda_);
|
|
outputData["nodalLambdaForce"] = &(nodalAtomicLambdaForce_);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class VelocityGlcFiltered
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
// Grab references to ATC and kinetostat data
|
|
//--------------------------------------------------------
|
|
VelocityGlcFiltered::VelocityGlcFiltered(Kinetostat *kinetostat)
|
|
: VelocityGlc(kinetostat),
|
|
nodalAtomicVelocities_(atcTransfer_->get_atomic_field(VELOCITY))
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_pre_filtering
|
|
// applies first step of filtering to
|
|
// relevant variables
|
|
//--------------------------------------------------------
|
|
void VelocityGlcFiltered::apply_pre_filtering(double dt)
|
|
{
|
|
// apply time filtered lambda to atomic fields
|
|
VelocityGlc::apply_pre_filtering(dt);
|
|
DENS_MAT nodalAcceleration(nNodes_,nsd_);
|
|
atcTransfer_->apply_inverse_md_mass_matrix(lambdaForceFiltered_,
|
|
nodalAcceleration,
|
|
VELOCITY);
|
|
nodalAtomicVelocities_ += dt*nodalAcceleration;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_kinetostat_rhs
|
|
// sets up the right-hand side of the
|
|
// kinetostat equations
|
|
//--------------------------------------------------------
|
|
void VelocityGlcFiltered::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
|
|
{
|
|
// form rhs : sum_a (hatN_Ia * x_ai) - (Upsilon)_Ii
|
|
double coef = 1./(timeFilter_->get_unfiltered_coefficient_pre_s1(dt));
|
|
rhs = coef*(atcTransfer_->get_mass_mat_md(VELOCITY))*(nodalAtomicVelocities_ - nodalVelocities_);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_nodal_lambda_force
|
|
// compute the effective FE force applied
|
|
// by the kinetostat
|
|
//--------------------------------------------------------
|
|
void VelocityGlcFiltered::compute_nodal_lambda_force(double dt)
|
|
{
|
|
atcTransfer_->restrict_volumetric_quantity(lambdaForce_,nodalAtomicLambdaForce_);
|
|
timeFilter_->apply_post_step1(lambdaForceFiltered_,nodalAtomicLambdaForce_,dt);
|
|
|
|
// update filtered atomic displacements
|
|
DENS_MAT nodalLambdaRoc(nodalAtomicLambdaForce_.nRows(),nodalAtomicLambdaForce_.nCols());
|
|
atcTransfer_->apply_inverse_md_mass_matrix(nodalAtomicLambdaForce_,
|
|
nodalLambdaRoc,
|
|
VELOCITY);
|
|
timeFilter_->apply_post_step1(nodalAtomicVelocities_,dt*nodalLambdaRoc,dt);
|
|
|
|
// update FE displacements for localized thermostats
|
|
apply_localization_correction(lambdaForceFiltered_,
|
|
nodalVelocities_,
|
|
dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// output:
|
|
// adds all relevant output to outputData
|
|
//--------------------------------------------------------
|
|
void VelocityGlcFiltered::output(double dt, OUTPUT_LIST & outputData)
|
|
{
|
|
outputData["lambda"] = &(lambda_);
|
|
outputData["nodalLambdaForce"] = &(lambdaForceFiltered_);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class StressFlux
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
// Grab references to ATC and kinetostat data
|
|
//--------------------------------------------------------
|
|
StressFlux::StressFlux(Kinetostat * kinetostat) :
|
|
GlcKinetostat(kinetostat),
|
|
nodalForce_(atcTransfer_->get_field_rhs(VELOCITY)),
|
|
nodalAtomicForce_(atcTransfer_->get_fe_atomic_field_roc(VELOCITY)),
|
|
momentumSource_(atcTransfer_->get_atomic_source(VELOCITY)),
|
|
v_(atcTransfer_->get_v()),
|
|
f_(atcTransfer_->get_f())
|
|
{
|
|
// flag for performing boundary flux calculation
|
|
if (kinetostat_->get_coupling_mode()==Kinetostat::FLUX)
|
|
fieldMask_(VELOCITY,FLUX) = true;
|
|
|
|
// sets up space for ghost force related variables
|
|
nodalGhostForce_.reset(nNodes_,nsd_);
|
|
nodalGhostForceFiltered_.reset(nNodes_,nsd_);
|
|
|
|
// NOTE ifdefs are for using reference lammps force as base pressure
|
|
#if false
|
|
int nLocalTotal = atcTransfer->get_nlocal_total();
|
|
int nsd = atcTransfer->get_nsd();
|
|
f0_ = new double*[nLocalTotal];
|
|
for (int i = 0; i < nLocalTotal; ++i) {
|
|
f0_[i] = new double[nsd];
|
|
for (int j = 0; j < nsd; ++j)
|
|
f0_[i][j] = f_[i][j];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
StressFlux::~StressFlux()
|
|
{
|
|
#if false
|
|
if (f0_) {
|
|
ATC_Transfer * atcTransfer = kinetostat_->get_atc_transfer();
|
|
int nLocalTotal = atcTransfer->get_nlocal_total();
|
|
for (int i = 0; i < nLocalTotal; ++i)
|
|
delete [] f0_[i];
|
|
delete [] f0_;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_pre_predictor:
|
|
// apply the kinetostat to the atoms in the
|
|
// mid-predictor integration phase
|
|
//--------------------------------------------------------
|
|
void StressFlux::apply_mid_predictor(double dt)
|
|
{
|
|
double dtLambda = 0.5*dt;
|
|
// apply lambda force to atoms
|
|
apply_to_atoms(v_,lambdaForce_,dtLambda);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_pre_corrector:
|
|
// apply the kinetostat to the atoms in the
|
|
// pre-corrector integration phase
|
|
//--------------------------------------------------------
|
|
void StressFlux::apply_pre_corrector(double dt)
|
|
{
|
|
// compute the kinetostat force
|
|
compute_kinetostat(dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_post_corrector:
|
|
// apply the kinetostat to the atoms in the
|
|
// post-corrector integration phase
|
|
//--------------------------------------------------------
|
|
void StressFlux::apply_post_corrector(double dt)
|
|
{
|
|
double dtLambda = 0.5*dt;
|
|
// apply lambda force to atoms
|
|
apply_to_atoms(v_,lambdaForce_,dtLambda);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_kinetostat
|
|
// manages the solution and application of the
|
|
// kinetostat equations and variables
|
|
//--------------------------------------------------------
|
|
void StressFlux::compute_kinetostat(double dt)
|
|
{
|
|
// set up ghost force
|
|
compute_ghost_force(nodalGhostForce_);
|
|
|
|
// initial filtering update
|
|
apply_pre_filtering(dt);
|
|
|
|
// set up rhs
|
|
DENS_MAT rhs(nNodes_,nsd_);
|
|
set_kinetostat_rhs(rhs,dt);
|
|
|
|
// solve linear system for lambda
|
|
solve_for_lambda(rhs);
|
|
|
|
// compute force applied by lambda
|
|
compute_lambda_force(lambdaForce_);
|
|
|
|
// compute nodal atomic power
|
|
compute_nodal_lambda_force(dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_pre_filtering
|
|
// applies first step of filtering to
|
|
// relevant variables
|
|
//--------------------------------------------------------
|
|
void StressFlux::apply_pre_filtering(double dt)
|
|
{
|
|
// apply time filtered lambda force
|
|
DENS_MAT lambdaZero(nNodes_,nsd_);
|
|
timeFilter_->apply_pre_step1(lambdaForceFiltered_,lambdaZero,dt);
|
|
timeFilter_->apply_pre_step1(nodalGhostForceFiltered_,nodalGhostForce_,dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// set_kinetostat_rhs
|
|
// sets up the RHS of the kinetostat equations
|
|
// for the coupling parameter lambda
|
|
//--------------------------------------------------------
|
|
void StressFlux::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
|
|
{
|
|
// (a) for flux based :
|
|
// form rhs : \int N_I r dV - \sum_g N_Ig^* f_g
|
|
// sources are set in ATC transfer
|
|
rhs.reset(nNodes_,nsd_);
|
|
rhs = momentumSource_ - nodalGhostForce_;
|
|
|
|
// (b) for ess. bcs
|
|
// NOTE can add check to see if set is empty for faster performance
|
|
// form rhs : {sum_a (N_Ia * f_ia) - M_md * (ddupsilon/dt)_I}
|
|
DENS_MAT rhsPrescribed = -1.*nodalForce_;
|
|
atcTransfer_->apply_inverse_mass_matrix(rhsPrescribed,VELOCITY);
|
|
rhsPrescribed = mdMassMatrix_*rhsPrescribed;
|
|
rhsPrescribed += nodalAtomicForce_;
|
|
|
|
set<pair<int,int> >::const_iterator iter;
|
|
for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
|
|
rhs(iter->first,iter->second) = rhsPrescribed(iter->first,iter->second);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_lambda_force
|
|
// computes the force induced by lambda
|
|
// on the atoms
|
|
//--------------------------------------------------------
|
|
void StressFlux::compute_lambda_force(DENS_MAT & lambdaForce)
|
|
{
|
|
if (nLocal_>0) {
|
|
// prolongation to (unique) nodes
|
|
lambdaForce.reset(nLocal_,nsd_);
|
|
atcTransfer_->prolong(lambda_,lambdaForce);
|
|
lambdaForce *= -1.;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_nodal_lambda_force
|
|
// computes the force induced on the FE
|
|
// by applying lambdaForce on the atoms
|
|
//--------------------------------------------------------
|
|
void StressFlux::compute_nodal_lambda_force(double dt)
|
|
{
|
|
atcTransfer_->restrict_volumetric_quantity(lambdaForce_,nodalAtomicLambdaForce_);
|
|
set<pair<int,int> >::const_iterator iter;
|
|
for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
|
|
nodalAtomicLambdaForce_(iter->first,iter->second) = 0.;
|
|
}
|
|
|
|
timeFilter_->apply_post_step1(lambdaForceFiltered_,nodalAtomicLambdaForce_,dt);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// add_to_rhs:
|
|
// determines what if any contributions to the
|
|
// finite element equations are needed for
|
|
// consistency with the kinetostat
|
|
//--------------------------------------------------------
|
|
void StressFlux::add_to_rhs(FIELDS & rhs)
|
|
{
|
|
rhs[VELOCITY] += nodalAtomicLambdaForce_ + boundaryFlux_[VELOCITY];
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// compute_ghost_force
|
|
// computes computes the restricted force on
|
|
// the ghost atoms
|
|
//--------------------------------------------------------
|
|
void StressFlux::compute_ghost_force(DENS_MAT & nodalGhostForce)
|
|
{
|
|
DENS_MAT nodalGhostForceLocal(nNodes_,nsd_);
|
|
nodalGhostForce.reset(nNodes_,nsd_);
|
|
|
|
if (nLocalGhost_ > 0) {
|
|
DENS_MAT ghostForce(nLocalGhost_,nsd_);
|
|
for (int i = 0; i < nLocalGhost_; i++) {
|
|
int atomIndex = ghostToAtom_(i);
|
|
for (int j = 0; j < nsd_; j++) {
|
|
ghostForce(i,j) = f_[atomIndex][j];
|
|
#if false
|
|
ghostForce(i,j) -= f0_[atomIndex][j];
|
|
#endif
|
|
}
|
|
}
|
|
nodalGhostForceLocal = shapeFunctionGhost_.transMat(ghostForce);
|
|
}
|
|
|
|
LammpsInterface::instance()->allsum(nodalGhostForceLocal.get_ptr(),
|
|
nodalGhostForce.get_ptr(), nodalGhostForce.size());
|
|
// convert from Lammps force units to ATC force units
|
|
nodalGhostForce *= LammpsInterface::instance()->ftm2v();
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_lambda_to_atoms
|
|
// uses existing lambda to modify given
|
|
// atomic quantity
|
|
//--------------------------------------------------------
|
|
void StressFlux::apply_to_atoms(double ** atomicVelocity,
|
|
const DENS_MAT & lambdaForce,
|
|
double dt)
|
|
{
|
|
if (nLocal_>0) {
|
|
// explicit update
|
|
for (int i = 0; i < nLocal_; i++) {
|
|
for (int j = 0; j < nsd_; j++) {
|
|
atomicVelocity[internalToAtom_(i)][j] += dt*lambdaForce(i,j)/atomicMass_(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// reset_filtered_ghost_force:
|
|
// resets the kinetostat generated ghost force to a
|
|
// prescribed value
|
|
//--------------------------------------------------------
|
|
void StressFlux::reset_filtered_ghost_force(DENS_MAT & target)
|
|
{
|
|
for (int i = 0; i < nNodes_; ++i)
|
|
for (int j = 0; j < nsd_; ++j)
|
|
nodalGhostForceFiltered_(i,j) = target(i,j);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// output:
|
|
// adds all relevant output to outputData
|
|
//--------------------------------------------------------
|
|
void StressFlux::output(double dt, OUTPUT_LIST & outputData)
|
|
{
|
|
outputData["lambda"] = &(lambda_);
|
|
outputData["nodalLambdaForce"] = &(nodalAtomicLambdaForce_);
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
// Class StressFluxFiltered
|
|
//--------------------------------------------------------
|
|
//--------------------------------------------------------
|
|
|
|
//--------------------------------------------------------
|
|
// Constructor
|
|
//--------------------------------------------------------
|
|
StressFluxFiltered::StressFluxFiltered(Kinetostat * kinetostat) :
|
|
StressFlux(kinetostat),
|
|
nodalAtomicVelocity_(atcTransfer_->get_atomic_field(VELOCITY))
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
#if false
|
|
//--------------------------------------------------------
|
|
// apply:
|
|
// apply the kinetostat to the atoms
|
|
//--------------------------------------------------------
|
|
void StressFluxFiltered::apply_pre_corrector(double dt)
|
|
{
|
|
// NOTE currently not implemented, below based on GlcVelocityFiltered
|
|
|
|
// get neccesary data
|
|
double coef = 1./(timeFilter_->get_unfiltered_coefficient_pre_s1(dt));
|
|
|
|
// form rhs : sum_a (hatN_Ia * x_ai) - (\dot{Upsilon})_Ii
|
|
DENS_MAT rhs(nNodes_,nsd_);
|
|
for (int i = 0; i < nNodes_; i++)
|
|
for (int j = 0; j < nsd_; j++)
|
|
rhs(i,j) += coef*(nodalAtomicVelocities_(i,j) - nodalVelocities_(i,j));
|
|
DENS_MAT rhsOverlap(nNodeOverlap_,nsd_);
|
|
atcTransfer_->map_unique_to_overlap(rhs, rhsOverlap);
|
|
|
|
// solve matrix equation and map back to all nodes
|
|
DENS_MAT lambdaOverlap(nNodeOverlap_,nsd_);
|
|
DIAG_MAT weights;
|
|
set_weights(weights);
|
|
solve_for_lambda(rhsOverlap, weights, lambdaOverlap);
|
|
atcTransfer_->map_overlap_to_unique(lambdaOverlap,lambda_);
|
|
|
|
// apply lambda to the atoms and nodal atomic fields
|
|
DENS_MAT lambdaRestricted(nNodes_,nsd_);
|
|
apply_lambda_to_atoms(v_,lambdaRestricted);
|
|
timeFilter_->apply_post_step1(nodalAtomicVelocities_,-1.*lambdaRestricted,dt);
|
|
timeFilter_->apply_post_step1(nodalLambdaForce_,(-1./dt)*lambdaRestricted,dt);
|
|
DENS_MAT nodalLambdaRoc(nodalLambdaForce_.nRows,nodalLambdaForce_.nCols());
|
|
atcTransfer_->apply_inverse_mass_matrix(nodalLambdaForce_,
|
|
nodalLambdaRoc,
|
|
VELOCITY);
|
|
atcTransfer_->apply_internal_atomic_source(nodalVelocities_,
|
|
nodalLambdaRoc,
|
|
dt);
|
|
|
|
}
|
|
#endif
|
|
// //--------------------------------------------------------
|
|
// // apply_pre_filtering
|
|
// // applies first step of filtering to
|
|
// // relevant variables
|
|
// //--------------------------------------------------------
|
|
// void StressFluxFiltered::apply_pre_filtering(double dt)
|
|
// {
|
|
// // apply time filtered lambda to atomic fields
|
|
// StressFlux::apply_pre_filtering(dt);
|
|
// nodalAtomicForce_ += lambdaForceFiltered;
|
|
// }
|
|
|
|
//--------------------------------------------------------
|
|
// set_kinetostat_rhs
|
|
// sets up the RHS of the kinetostat equations
|
|
// for the coupling parameter lambda
|
|
//--------------------------------------------------------
|
|
void StressFluxFiltered::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
|
|
{
|
|
// set basic terms
|
|
// (a) for flux based :
|
|
// form rhs : \int N_I r dV - \sum_g N_Ig^* f_g
|
|
// sources are set in ATC transfer
|
|
rhs.reset(nNodes_,nsd_);
|
|
rhs = momentumSource_ - nodalGhostForceFiltered_;
|
|
|
|
// (b) for ess. bcs
|
|
// NOTE can add check to see if set is empty for faster performance
|
|
// form rhs : {sum_a (N_Ia * f_ia) - M_md * (ddupsilon/dt)_I}
|
|
DENS_MAT rhsPrescribed = -1.*nodalForce_;
|
|
atcTransfer_->apply_inverse_mass_matrix(rhsPrescribed,VELOCITY);
|
|
rhsPrescribed = mdMassMatrix_*rhsPrescribed;
|
|
rhsPrescribed += nodalAtomicForce_;
|
|
|
|
set<pair<int,int> >::const_iterator iter;
|
|
for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
|
|
rhs(iter->first,iter->second) = rhsPrescribed(iter->first,iter->second);
|
|
}
|
|
|
|
// adjust for application of current lambda force
|
|
rhs += lambdaForceFiltered_;
|
|
|
|
// correct for time filtering
|
|
rhs *= 1./(timeFilter_->get_unfiltered_coefficient_pre_s1(dt));
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// apply_lambda_to_atoms
|
|
// uses existing lambda to modify given
|
|
// atomic quantity
|
|
//--------------------------------------------------------
|
|
void StressFluxFiltered::apply_to_atoms(double ** atomicVelocity,
|
|
const DENS_MAT & lambdaForce,
|
|
double dt)
|
|
{
|
|
StressFlux::apply_to_atoms(atomicVelocity,lambdaForce,dt);
|
|
|
|
// add in corrections to filtered nodal atomice velocity
|
|
DENS_MAT velocityRoc(nNodes_,nsd_);
|
|
atcTransfer_->apply_inverse_md_mass_matrix(lambdaForceFiltered_,
|
|
velocityRoc,
|
|
VELOCITY);
|
|
nodalAtomicVelocity_ += dt*velocityRoc;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// add_to_rhs:
|
|
// determines what if any contributions to the
|
|
// finite element equations are needed for
|
|
// consistency with the kinetostat
|
|
//--------------------------------------------------------
|
|
void StressFluxFiltered::add_to_rhs(FIELDS & rhs)
|
|
{
|
|
rhs[VELOCITY] += lambdaForceFiltered_ + boundaryFlux_[VELOCITY];
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
// output:
|
|
// adds all relevant output to outputData
|
|
//--------------------------------------------------------
|
|
void StressFluxFiltered::output(double dt, OUTPUT_LIST & outputData)
|
|
{
|
|
outputData["lambda"] = &(lambda_);
|
|
outputData["nodalLambdaForce"] = &(lambdaForceFiltered_);
|
|
}
|
|
|
|
};
|