1218
1444
//--------------------------------------------------------
1219
1445
void StressFluxFiltered::add_to_rhs(FIELDS & rhs)
1221
rhs[VELOCITY] += lambdaForceFiltered_ + boundaryFlux_[VELOCITY];
1224
//--------------------------------------------------------
1226
// adds all relevant output to outputData
1227
//--------------------------------------------------------
1228
void StressFluxFiltered::output(double dt, OUTPUT_LIST & outputData)
1230
outputData["lambda"] = &(lambda_);
1231
outputData["nodalLambdaForce"] = &(lambdaForceFiltered_);
1447
// compute kinetostat forces
1448
compute_kinetostat(atc_->dt());
1449
rhs[VELOCITY] += lambdaForceFiltered_->quantity() + boundaryFlux_[VELOCITY].quantity();
1452
//--------------------------------------------------------
1454
// adds all relevant output to outputData
1455
//--------------------------------------------------------
1456
void StressFluxFiltered::output(OUTPUT_LIST & outputData)
1458
DENS_MAT & lambda(lambda_->set_quantity());
1459
DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
1460
if ((atc_->lammps_interface())->rank_zero()) {
1461
outputData[regulatorPrefix_+"Lambda"] = λ
1462
outputData[regulatorPrefix_+"NodalLambdaForce"] = &lambdaForceFiltered;
1466
//--------------------------------------------------------
1467
//--------------------------------------------------------
1468
// Class KinetostatGlcFs
1469
//--------------------------------------------------------
1470
//--------------------------------------------------------
1472
//--------------------------------------------------------
1474
// Grab references to ATC and kinetostat data
1475
//--------------------------------------------------------
1476
KinetostatGlcFs::KinetostatGlcFs(Kinetostat * kinetostat,
1477
const string & regulatorPrefix) :
1478
KinetostatShapeFunction(kinetostat,regulatorPrefix),
1479
velocity_(atc_->field(VELOCITY))
1481
// constuct/obtain data corresponding to stage 3 of ATC_Method::initialize
1482
nodalAtomicLambdaForce_ = kinetostat_->regulator_data(regulatorPrefix_+"NodalAtomicLambdaForce",nsd_);
1485
//--------------------------------------------------------
1486
// constructor_transfers
1487
// instantiates or obtains all dependency managed data
1488
//--------------------------------------------------------
1489
void KinetostatGlcFs::construct_transfers()
1491
InterscaleManager & interscaleManager(atc_->interscale_manager());
1493
// base class transfers
1494
KinetostatShapeFunction::construct_transfers();
1496
// get data from manager
1497
nodalAtomicMomentum_ = interscaleManager.dense_matrix("NodalAtomicMomentum");
1499
// atomic force induced by kinetostat
1500
PerAtomQuantity<double> * atomLambdas = interscaleManager.per_atom_quantity(regulatorPrefix_+"AtomLambdaMomentum");
1501
atomKinetostatForce_ = new AtomicKinetostatForceStress(atc_,atomLambdas);
1502
interscaleManager.add_per_atom_quantity(atomKinetostatForce_,
1503
regulatorPrefix_+"AtomKinetostatForce");
1506
//--------------------------------------------------------
1508
// initializes all method data
1509
//--------------------------------------------------------
1510
void KinetostatGlcFs::initialize()
1512
KinetostatShapeFunction::initialize();
1514
// set up workspaces
1515
_deltaMomentum_.reset(nNodes_,nsd_);
1516
_lambdaForceOutput_.reset(nNodes_,nsd_);
1518
TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
1519
if (!timeFilterManager->end_equilibrate()) {
1520
// we should reset lambda and lambdaForce to zero in this case
1521
// implies an initial condition of 0 for the filtered nodal lambda power
1522
// initial conditions will always be needed when using time filtering
1523
// however, the fractional step scheme must assume the instantaneous
1524
// nodal lambda power is 0 initially because all quantities are in delta form
1525
*lambda_ = 0.; // ensures initial lambda force is zero
1526
*nodalAtomicLambdaForce_ = 0.; // momentum change due to kinetostat
1527
*lambdaForceFiltered_ = 0.; // filtered momentum change due to kinetostats
1530
// we can grab lambda power variables using time integrator and atc transfer in cases for equilibration
1533
// sets up time filter for cases where variables temporally filtered
1534
if (timeFilterManager->need_reset()) {
1535
// the form of this integrator implies no time filters that require history data can be used
1536
timeFilter_->initialize(nodalAtomicLambdaForce_->quantity());
1542
//--------------------------------------------------------
1544
// creates mapping from all nodes to those to which
1545
// the kinetostat applies
1546
//--------------------------------------------------------
1547
void KinetostatGlcFs::compute_rhs_map()
1549
rhsMap_.resize(overlapToNodeMap_->nRows(),1);
1550
DENS_MAT rhsMapGlobal(nNodes_,1);
1551
const set<int> & applicationNodes(applicationNodes_->quantity());
1552
for (int i = 0; i < nNodes_; i++) {
1553
if (applicationNodes.find(i) != applicationNodes.end()) {
1554
rhsMapGlobal(i,0) = 1.;
1557
rhsMapGlobal(i,0) = 0.;
1560
map_unique_to_overlap(rhsMapGlobal,rhsMap_);
1563
//--------------------------------------------------------
1564
// apply_pre_predictor:
1565
// apply the kinetostat to the atoms in the
1566
// pre-predictor integration phase
1567
//--------------------------------------------------------
1568
void KinetostatGlcFs::apply_pre_predictor(double dt)
1570
DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
1571
DENS_MAT & nodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
1573
// update filtered forces
1574
timeFilter_->apply_pre_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
1576
// apply lambda force to atoms and compute instantaneous lambda force
1577
this->apply_to_atoms(atomVelocities_,nodalAtomicMomentum_,
1578
atomKinetostatForce_->quantity(),
1579
nodalAtomicLambdaForce,0.5*dt);
1581
// update nodal variables for first half of timestep
1582
this->add_to_momentum(nodalAtomicLambdaForce,_deltaMomentum_,0.5*dt);
1583
atc_->apply_inverse_mass_matrix(_deltaMomentum_,VELOCITY);
1584
velocity_ += _deltaMomentum_;
1586
// start update of filtered lambda force
1587
nodalAtomicLambdaForce = 0.;
1588
timeFilter_->apply_post_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
1591
//--------------------------------------------------------
1592
// apply_post_corrector:
1593
// apply the kinetostat to the atoms in the
1594
// post-corrector integration phase
1595
//--------------------------------------------------------
1596
void KinetostatGlcFs::apply_post_corrector(double dt)
1598
// compute the kinetostat equation and update lambda
1599
this->compute_lambda(dt);
1601
DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
1602
DENS_MAT & nodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
1604
// update filtered force
1605
timeFilter_->apply_pre_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
1607
// apply lambda force to atoms and compute instantaneous lambda force
1608
this->apply_to_atoms(atomVelocities_,nodalAtomicMomentum_,
1609
atomKinetostatForce_->quantity(),
1610
nodalAtomicLambdaForce,0.5*dt);
1612
// update nodal variables for first half of timestep
1613
this->add_to_momentum(nodalAtomicLambdaForce,_deltaMomentum_,0.5*dt);
1614
nodalAtomicLambdaForce *= 2./dt;
1615
atc_->apply_inverse_mass_matrix(_deltaMomentum_,VELOCITY);
1616
velocity_ += _deltaMomentum_;
1618
// start update of filtered lambda force
1619
timeFilter_->apply_post_step2(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
1622
//--------------------------------------------------------
1623
// compute_kinetostat
1624
// manages the solution and application of the
1625
// kinetostat equations and variables
1626
//--------------------------------------------------------
1627
void KinetostatGlcFs::compute_lambda(double dt)
1629
// set up rhs for lambda equation
1630
this->set_kinetostat_rhs(rhs_,0.5*dt);
1632
// solve linear system for lambda
1633
DENS_MAT & lambda(lambda_->set_quantity());
1634
solve_for_lambda(rhs_,lambda);
1637
//--------------------------------------------------------
1638
// apply_lambda_to_atoms
1639
// uses existing lambda to modify given
1641
//--------------------------------------------------------
1642
void KinetostatGlcFs::apply_to_atoms(PerAtomQuantity<double> * atomVelocity,
1643
const DENS_MAN * nodalAtomicMomentum,
1644
const DENS_MAT & lambdaForce,
1645
DENS_MAT & nodalAtomicLambdaForce,
1648
// compute initial contributions to lambda force
1649
nodalAtomicLambdaForce = nodalAtomicMomentum->quantity();
1650
nodalAtomicLambdaForce *= -1.;
1652
// apply lambda force to atoms
1653
_velocityDelta_ = lambdaForce;
1654
_velocityDelta_ /= atomMasses_->quantity();
1655
_velocityDelta_ *= dt;
1656
(*atomVelocity) += _velocityDelta_;
1658
// finalize lambda force
1659
nodalAtomicLambdaForce += nodalAtomicMomentum->quantity();
1662
//--------------------------------------------------------
1664
// adds all relevant output to outputData
1665
//--------------------------------------------------------
1666
void KinetostatGlcFs::output(OUTPUT_LIST & outputData)
1668
_lambdaForceOutput_ = nodalAtomicLambdaForce_->quantity();
1669
// approximate value for lambda force
1670
double dt = LammpsInterface::instance()->dt();
1671
_lambdaForceOutput_ *= (2./dt);
1672
DENS_MAT & lambda(lambda_->set_quantity());
1673
if ((atc_->lammps_interface())->rank_zero()) {
1674
outputData[regulatorPrefix_+"Lambda"] = λ
1675
outputData[regulatorPrefix_+"NodalLambdaForce"] = &(_lambdaForceOutput_);
1679
//--------------------------------------------------------
1680
//--------------------------------------------------------
1681
// Class KinetostatFlux
1682
//--------------------------------------------------------
1683
//--------------------------------------------------------
1685
//--------------------------------------------------------
1687
// Grab references to ATC and kinetostat data
1688
//--------------------------------------------------------
1689
KinetostatFlux::KinetostatFlux(Kinetostat * kinetostat,
1690
const string & regulatorPrefix) :
1691
KinetostatGlcFs(kinetostat,regulatorPrefix),
1692
momentumSource_(atc_->atomic_source(VELOCITY)),
1693
nodalGhostForce_(NULL),
1694
nodalGhostForceFiltered_(NULL)
1696
// flag for performing boundary flux calculation
1697
fieldMask_(VELOCITY,FLUX) = true;
1699
// constuct/obtain data corresponding to stage 3 of ATC_Method::initialize
1700
nodalGhostForceFiltered_ = kinetostat_->regulator_data(regulatorPrefix_+"NodalGhostForceFiltered",nsd_);
1703
//--------------------------------------------------------
1704
// constructor_transfers
1705
// instantiates or obtains all dependency managed data
1706
//--------------------------------------------------------
1707
void KinetostatFlux::construct_transfers()
1709
InterscaleManager & interscaleManager(atc_->interscale_manager());
1711
// set up node mappings
1715
// set up linear solver
1716
// set up data for linear solver
1717
shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
1718
interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
1719
regulatorPrefix_+"LambdaCouplingMatrixMomentum");
1721
lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
1722
interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
1723
regulatorPrefix_+"LambdaAtomMap");
1725
if (atomicRegulator_->use_localized_lambda()) {
1726
linearSolverType_ = AtomicRegulator::RSL_SOLVE;
1729
linearSolverType_ = AtomicRegulator::CG_SOLVE;
1732
// base class transfers
1733
KinetostatGlcFs::construct_transfers();
1735
// sets up space for ghost force related variables
1736
if (atc_->groupbit_ghost()) {
1737
MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap =
1738
interscaleManager.dense_matrix_int(regulatorPrefix_+"NodeToOverlapMap");
1739
GhostCouplingMatrix * shapeFunctionGhost = new GhostCouplingMatrix(atc_,interscaleManager.per_atom_sparse_matrix("InterpolantGhost"),
1742
interscaleManager.add_sparse_matrix(shapeFunctionGhost,
1743
regulatorPrefix_+"GhostCouplingMatrix");
1744
FundamentalAtomQuantity * atomGhostForce = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE,
1746
nodalGhostForce_ = new AtfShapeFunctionRestriction(atc_,atomGhostForce,
1747
shapeFunctionGhost);
1748
interscaleManager.add_dense_matrix(nodalGhostForce_,
1749
regulatorPrefix_+"NodalGhostForce");
1753
//--------------------------------------------------------
1755
// initializes all method data
1756
//--------------------------------------------------------
1757
void KinetostatFlux::initialize()
1759
KinetostatGlcFs::initialize();
1761
TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
1762
if (!timeFilterManager->end_equilibrate()) {
1763
// we should reset lambda and lambdaForce to zero in this case
1764
// implies an initial condition of 0 for the filtered nodal lambda power
1765
// initial conditions will always be needed when using time filtering
1766
// however, the fractional step scheme must assume the instantaneous
1767
// nodal lambda power is 0 initially because all quantities are in delta form
1768
*nodalGhostForceFiltered_ = 0.; // filtered force from ghost atoms
1771
// we can grab lambda power variables using time integrator and atc transfer in cases for equilibration
1775
//--------------------------------------------------------
1776
// construct_regulated_nodes:
1777
// constructs the set of nodes being regulated
1778
//--------------------------------------------------------
1779
void KinetostatFlux::construct_regulated_nodes()
1781
InterscaleManager & interscaleManager(atc_->interscale_manager());
1783
// matrix requires all entries even if localized for correct lumping
1784
regulatedNodes_ = new RegulatedNodes(atc_);
1785
interscaleManager.add_set_int(regulatedNodes_,
1786
regulatorPrefix_+"KinetostatRegulatedNodes");
1788
// if localized monitor nodes with applied fluxes
1789
if (atomicRegulator_->use_localized_lambda()) {
1790
if ((kinetostat_->coupling_mode() == Kinetostat::FLUX) && (atomicRegulator_->boundary_integration_type() != NO_QUADRATURE)) {
1791
// include boundary nodes
1792
applicationNodes_ = new FluxBoundaryNodes(atc_);
1794
boundaryNodes_ = new BoundaryNodes(atc_);
1795
interscaleManager.add_set_int(boundaryNodes_,
1796
regulatorPrefix_+"KinetostatBoundaryNodes");
1799
// fluxed nodes only
1800
applicationNodes_ = new FluxNodes(atc_);
1802
interscaleManager.add_set_int(applicationNodes_,
1803
regulatorPrefix_+"KinetostatApplicationNodes");
1806
applicationNodes_ = regulatedNodes_;
1809
// special set of boundary elements for boundary flux quadrature
1810
if ((atomicRegulator_->boundary_integration_type() == FE_INTERPOLATION)
1811
&& (atomicRegulator_->use_localized_lambda())) {
1812
elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
1813
interscaleManager.add_dense_matrix_bool(elementMask_,
1814
regulatorPrefix_+"BoundaryElementMask");
1818
//--------------------------------------------------------
1819
// apply_pre_predictor:
1820
// apply the kinetostat to the atoms in the
1821
// pre-predictor integration phase
1822
//--------------------------------------------------------
1823
void KinetostatFlux::apply_pre_predictor(double dt)
1825
// update filtered forces
1826
if (nodalGhostForce_) {
1827
timeFilter_->apply_pre_step1(nodalGhostForceFiltered_->set_quantity(),
1828
nodalGhostForce_->quantity(),dt);
1831
KinetostatGlcFs::apply_pre_predictor(dt);
1834
//--------------------------------------------------------
1835
// apply_post_corrector:
1836
// apply the kinetostat to the atoms in the
1837
// post-corrector integration phase
1838
//--------------------------------------------------------
1839
void KinetostatFlux::apply_post_corrector(double dt)
1841
// update filtered ghost force
1842
if (nodalGhostForce_) {
1843
timeFilter_->apply_post_step1(nodalGhostForceFiltered_->set_quantity(),
1844
nodalGhostForce_->quantity(),dt);
1847
// compute the kinetostat equation and update lambda
1848
KinetostatGlcFs::apply_post_corrector(dt);
1851
//--------------------------------------------------------
1852
// set_kinetostat_rhs
1853
// sets up the RHS of the kinetostat equations
1854
// for the coupling parameter lambda
1855
//--------------------------------------------------------
1856
void KinetostatFlux::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
1858
// (a) for flux based :
1859
// form rhs : \int N_I r dV - \sum_g N_Ig^* f_g
1860
// sources are set in ATC transfer
1861
rhs.reset(nNodes_,nsd_);
1862
const DENS_MAT & momentumSource(momentumSource_.quantity());
1863
const set<int> & applicationNodes(applicationNodes_->quantity());
1864
set<int>::const_iterator iNode;
1865
for (iNode = applicationNodes.begin(); iNode != applicationNodes.end(); iNode++) {
1866
for (int j = 0; j < nsd_; j++) {
1867
rhs(*iNode,j) = momentumSource(*iNode,j);
1871
// add ghost forces, if needed
1872
if (nodalGhostForce_) {
1873
const DENS_MAT & nodalGhostForce(nodalGhostForce_->quantity());
1874
for (iNode = applicationNodes.begin(); iNode != applicationNodes.end(); iNode++) {
1875
for (int j = 0; j < nsd_; j++) {
1876
rhs(*iNode,j) -= nodalGhostForce(*iNode,j);
1882
//--------------------------------------------------------
1884
// determines what if any contributions to the
1885
// finite element equations are needed for
1886
// consistency with the kinetostat
1887
//--------------------------------------------------------
1888
void KinetostatFlux::add_to_momentum(const DENS_MAT & nodalLambdaForce,
1889
DENS_MAT & deltaMomentum,
1892
deltaMomentum.resize(nNodes_,nsd_);
1893
const DENS_MAT & boundaryFlux(boundaryFlux_[VELOCITY].quantity());
1894
for (int i = 0; i < nNodes_; i++) {
1895
for (int j = 0; j < nsd_; j++) {
1896
deltaMomentum(i,j) = nodalLambdaForce(i,j) + dt*boundaryFlux(i,j);
1901
//--------------------------------------------------------
1902
// reset_filtered_ghost_force:
1903
// resets the kinetostat generated ghost force to a
1905
//--------------------------------------------------------
1906
void KinetostatFlux::reset_filtered_ghost_force(DENS_MAT & target)
1908
(*nodalGhostForceFiltered_) = target;
1911
//--------------------------------------------------------
1912
//--------------------------------------------------------
1913
// Class KinetostatFluxGhost
1914
//--------------------------------------------------------
1915
//--------------------------------------------------------
1917
//--------------------------------------------------------
1919
// Grab references to ATC and kinetostat data
1920
//--------------------------------------------------------
1921
KinetostatFluxGhost::KinetostatFluxGhost(Kinetostat * kinetostat,
1922
const string & regulatorPrefix) :
1923
KinetostatFlux(kinetostat,regulatorPrefix)
1925
// flag for performing boundary flux calculation
1926
fieldMask_(VELOCITY,FLUX) = false;
1929
//--------------------------------------------------------
1930
// constructor_transfers
1931
// instantiates or obtains all dependency managed data
1932
//--------------------------------------------------------
1933
void KinetostatFluxGhost::construct_transfers()
1935
KinetostatFlux::construct_transfers();
1936
if (!nodalGhostForce_) {
1937
throw ATC_Error("StressFluxGhost::StressFluxGhost - ghost atoms must be specified");
1941
//--------------------------------------------------------
1942
// compute_boundary_flux:
1943
// computes the boundary flux to be consistent with
1945
//--------------------------------------------------------
1946
void KinetostatFluxGhost::compute_boundary_flux(FIELDS & fields)
1948
// This is only used in computation of atomic sources
1949
boundaryFlux_[VELOCITY] = 0.;
1952
//--------------------------------------------------------
1954
// determines what if any contributions to the
1955
// finite element equations are needed for
1956
// consistency with the kinetostat
1957
//--------------------------------------------------------
1958
void KinetostatFluxGhost::add_to_momentum(const DENS_MAT & nodalLambdaForce,
1959
DENS_MAT & deltaMomentum,
1962
deltaMomentum.resize(nNodes_,nsd_);
1963
const DENS_MAT & boundaryFlux(nodalGhostForce_->quantity());
1964
for (int i = 0; i < nNodes_; i++) {
1965
for (int j = 0; j < nsd_; j++) {
1966
deltaMomentum(i,j) = nodalLambdaForce(i,j) + dt*boundaryFlux(i,j);
1971
//--------------------------------------------------------
1972
// set_kinetostat_rhs
1973
// sets up the RHS of the kinetostat equations
1974
// for the coupling parameter lambda
1975
//--------------------------------------------------------
1976
void KinetostatFluxGhost::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
1978
// (a) for flux based :
1979
// form rhs : \int N_I r dV - \sum_g N_Ig^* f_g
1980
// sources are set in ATC transfer
1981
rhs.reset(nNodes_,nsd_);
1982
const DENS_MAT & momentumSource(momentumSource_.quantity());
1983
const set<int> & applicationNodes(applicationNodes_->quantity());
1984
set<int>::const_iterator iNode;
1985
for (iNode = applicationNodes.begin(); iNode != applicationNodes.end(); iNode++) {
1986
for (int j = 0; j < nsd_; j++) {
1987
rhs(*iNode,j) = momentumSource(*iNode,j);
1992
//--------------------------------------------------------
1993
//--------------------------------------------------------
1994
// Class KinetostatFixed
1995
//--------------------------------------------------------
1996
//--------------------------------------------------------
1998
//--------------------------------------------------------
2000
// Grab references to ATC and kinetostat data
2001
//--------------------------------------------------------
2002
KinetostatFixed::KinetostatFixed(Kinetostat * kinetostat,
2003
const string & regulatorPrefix) :
2004
KinetostatGlcFs(kinetostat,regulatorPrefix),
2005
mdMassMatrix_(atc_->set_mass_mat_md(VELOCITY)),
2006
isFirstTimestep_(true)
2011
//--------------------------------------------------------
2012
// constructor_transfers
2013
// instantiates or obtains all dependency managed data
2014
//--------------------------------------------------------
2015
void KinetostatFixed::construct_transfers()
2017
InterscaleManager & interscaleManager(atc_->interscale_manager());
2019
// set up node mappings
2022
// determine if map is needed and set up if so
2023
if (this->use_local_shape_functions()) {
2024
lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
2025
interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
2026
regulatorPrefix_+"LambdaAtomMap");
2027
shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
2032
shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
2034
interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
2035
regulatorPrefix_+"LambdaCouplingMatrixMomentum");
2036
linearSolverType_ = AtomicRegulator::CG_SOLVE;
2038
// base class transfers
2039
KinetostatGlcFs::construct_transfers();
2042
//--------------------------------------------------------
2044
// initializes all method data
2045
//--------------------------------------------------------
2046
void KinetostatFixed::initialize()
2048
KinetostatGlcFs::initialize();
2050
// reset data to zero
2051
deltaFeMomentum_.reset(nNodes_,nsd_);
2052
deltaNodalAtomicMomentum_.reset(nNodes_,nsd_);
2055
//--------------------------------------------------------
2057
// flag to halve the lambda force for improved
2059
//--------------------------------------------------------
2060
bool KinetostatFixed::halve_force()
2062
if (isFirstTimestep_ || ((atc_->atom_to_element_map_type() == EULERIAN)
2063
&& (atc_->atom_to_element_map_frequency() > 1)
2064
&& (atc_->step() % atc_->atom_to_element_map_frequency() == 1))) {
2070
//--------------------------------------------------------
2071
// construct_regulated_nodes:
2072
// constructs the set of nodes being regulated
2073
//--------------------------------------------------------
2074
void KinetostatFixed::construct_regulated_nodes()
2076
InterscaleManager & interscaleManager(atc_->interscale_manager());
2078
if (!atomicRegulator_->use_localized_lambda()) {
2079
regulatedNodes_ = new RegulatedNodes(atc_);
2081
else if (kinetostat_->coupling_mode() == Kinetostat::FLUX) {
2082
regulatedNodes_ = new FixedNodes(atc_);
2084
else if (kinetostat_->coupling_mode() == Kinetostat::FIXED) {
2085
// include boundary nodes
2086
regulatedNodes_ = new FixedBoundaryNodes(atc_);
2089
throw ATC_Error("ThermostatFixed::construct_regulated_nodes - couldn't determine set of regulated nodes");
2092
interscaleManager.add_set_int(regulatedNodes_,
2093
regulatorPrefix_+"RegulatedNodes");
2095
applicationNodes_ = regulatedNodes_;
2097
// special set of boundary elements for defining regulated atoms
2098
if (atomicRegulator_->use_localized_lambda()) {
2099
elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
2100
interscaleManager.add_dense_matrix_bool(elementMask_,
2101
regulatorPrefix_+"BoundaryElementMask");
2105
//--------------------------------------------------------
2106
// initialize_delta_nodal_atomic_momentum:
2107
// initializes storage for the variable tracking
2108
// the change in the nodal atomic momentum
2109
// that has occured over the past timestep
2110
//--------------------------------------------------------
2111
void KinetostatFixed::initialize_delta_nodal_atomic_momentum(double dt)
2113
// initialize delta energy
2114
const DENS_MAT & myNodalAtomicMomentum(nodalAtomicMomentum_->quantity());
2115
initialNodalAtomicMomentum_ = myNodalAtomicMomentum;
2116
initialNodalAtomicMomentum_ *= -1.; // initially stored as negative for efficiency
2117
timeFilter_->apply_pre_step1(nodalAtomicMomentumFiltered_.set_quantity(),
2118
myNodalAtomicMomentum,dt);
2121
//--------------------------------------------------------
2122
// compute_delta_nodal_atomic_momentum:
2123
// computes the change in the nodal atomic momentum
2124
// that has occured over the past timestep
2125
//--------------------------------------------------------
2126
void KinetostatFixed::compute_delta_nodal_atomic_momentum(double dt)
2128
// set delta energy based on predicted atomic velocities
2129
const DENS_MAT & myNodalAtomicMomentum(nodalAtomicMomentum_->quantity());
2130
timeFilter_->apply_post_step1(nodalAtomicMomentumFiltered_.set_quantity(),
2131
myNodalAtomicMomentum,dt);
2132
deltaNodalAtomicMomentum_ = initialNodalAtomicMomentum_;
2133
deltaNodalAtomicMomentum_ += myNodalAtomicMomentum;
2136
//--------------------------------------------------------
2137
// apply_pre_predictor:
2138
// apply the kinetostat to the atoms in the
2139
// pre-predictor integration phase
2140
//--------------------------------------------------------
2141
void KinetostatFixed::apply_pre_predictor(double dt)
2143
// initialize values to be track change in finite element energy over the timestep
2144
initialize_delta_nodal_atomic_momentum(dt);
2145
initialFeMomentum_ = -1.*((mdMassMatrix_.quantity())*(velocity_.quantity())); // initially stored as negative for efficiency
2147
KinetostatGlcFs::apply_pre_predictor(dt);
2150
//--------------------------------------------------------
2151
// apply_post_corrector:
2152
// apply the kinetostat to the atoms in the
2153
// post-corrector integration phase
2154
//--------------------------------------------------------
2155
void KinetostatFixed::apply_post_corrector(double dt)
2157
KinetostatGlcFs::apply_post_corrector(dt);
2159
// update filtered momentum with lambda force
2160
DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
2161
timeFilter_->apply_post_step2(nodalAtomicMomentumFiltered_.set_quantity(),
2162
myNodalAtomicLambdaForce,dt);
2164
if (halve_force()) {
2165
// Halve lambda force due to fixed temperature constraints
2166
// 1) makes up for poor initial condition
2167
// 2) accounts for possibly large value of lambda when atomic shape function values change
2168
// from eulerian mapping after more than 1 timestep
2169
// avoids unstable oscillations arising from
2170
// thermostat having to correct for error introduced in lambda changing the
2171
// shape function matrices
2175
isFirstTimestep_ = false;
2178
//--------------------------------------------------------
2179
// compute_kinetostat
2180
// manages the solution and application of the
2181
// kinetostat equations and variables
2182
//--------------------------------------------------------
2183
void KinetostatFixed::compute_lambda(double dt)
2185
// compute predicted changes in nodal atomic momentum
2186
compute_delta_nodal_atomic_momentum(dt);
2188
// change in finite element momentum
2189
deltaFeMomentum_ = initialFeMomentum_;
2190
deltaFeMomentum_ += (mdMassMatrix_.quantity())*(velocity_.quantity());
2192
// set up rhs for lambda equation
2193
KinetostatGlcFs::compute_lambda(dt);
2196
//--------------------------------------------------------
2197
// set_kinetostat_rhs
2198
// sets up the RHS of the kinetostat equations
2199
// for the coupling parameter lambda
2200
//--------------------------------------------------------
2201
void KinetostatFixed::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
2203
// for essential bcs (fixed nodes) :
2204
// form rhs : (delUpsV - delUps)/dt
2205
const set<int> & regulatedNodes(regulatedNodes_->quantity());
2206
double factor = (1./dt);
2207
for (int i = 0; i < nNodes_; i++) {
2208
if (regulatedNodes.find(i) != regulatedNodes.end()) {
2209
for (int j = 0; j < nsd_; j++) {
2210
rhs(i,j) = factor*(deltaNodalAtomicMomentum_(i,j) - deltaFeMomentum_(i,j));
2214
for (int j = 0; j < nsd_; j++) {
2221
//--------------------------------------------------------
2223
// determines what if any contributions to the
2224
// finite element equations are needed for
2225
// consistency with the kinetostat
2226
//--------------------------------------------------------
2227
void KinetostatFixed::add_to_momentum(const DENS_MAT & nodalLambdaForce,
2228
DENS_MAT & deltaMomentum,
2231
deltaMomentum.resize(nNodes_,nsd_);
2232
const set<int> & regulatedNodes(regulatedNodes_->quantity());
2233
for (int i = 0; i < nNodes_; i++) {
2234
if (regulatedNodes.find(i) != regulatedNodes.end()) {
2235
for (int j = 0; j < nsd_; j++) {
2236
deltaMomentum(i,j) = 0.;
2240
for (int j = 0; j < nsd_; j++) {
2241
deltaMomentum(i,j) = nodalLambdaForce(i,j);