CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
LatticeMap.cc
Go to the documentation of this file.
3 namespace CASM {
4  LatticeMap::LatticeMap(const Lattice &_ideal, const Lattice &_strained, Index num_atoms, double _tol/*=TOL*/, int _range/*=2*/) :
5  m_L1(Eigen::Matrix3d(_ideal.get_reduced_cell().lat_column_mat())), m_L2(Eigen::Matrix3d(_strained.get_reduced_cell().lat_column_mat())),
6  m_scale(pow(std::abs(m_L2.determinant() / m_L1.determinant()), 1.0 / 3.0)), m_atomic_vol(std::abs(m_L2.determinant() / (double)num_atoms)), m_tol(_tol), m_cost(1e20),
7  m_inv_count(-std::abs(_range) * IMatType::Ones(3, 3), std::abs(_range) * IMatType::Ones(3, 3), IMatType::Ones(3, 3)) {
8 
10  m_V_inv = m_L2.inverse() * Eigen::Matrix3d(_strained.lat_column_mat());
11  // Initialize to first valid mapping
13  }
14 
15  //*******************************************************************************************
16  /*
17  * For L_strained = (*this).lat_column_mat() and L_ideal = _ideal_lat.lat_column_mat(), we find the mapping:
18  *
19  * L_strained = F * L_ideal * N -- (Where 'N' is an integer matrix of determinant=1)
20  *
21  * That minimizes the cost function:
22  *
23  * C = pow((*this).volume(),2/3) * trace(E_dev.transpose()*E_dev.transpose()) / 4
24  *
25  * Where E_dev is the non-volumetric component of the green-lagrange strain
26  *
27  * E_dev = E - trace(E/3)*Identity -- (such that E_dev is traceless)
28  *
29  * where the Green-Lagrange strain is
30  *
31  * E = (F.transpose()*F-Identity)/2
32  *
33  * The cost function approximates the mean-square-displacement of a point in a cube of volume (*this).volume() when it is
34  * deformed by deformation matrix 'F', but neglecting volumetric effects
35  *
36  * The algorithm proceeds by counting over 'N' matrices (integer matrices of determinant 1) with elements on the interval (-2,2).
37  * (we actually count over N.inverse(), because....)
38  *
39  * The green-lagrange strain for that 'N' is then found using the relation
40  *
41  * F.transpose()*F = L_ideal.inverse().transpose()*N.inverse().transpose()*L_strained.transpose()*L_strained*N.inverse()*L_ideal.inverse()
42  *
43  * The minimal 'C' is returned at the end of the optimization.
44  */
45  //*******************************************************************************************
46 
48  m_inv_count.reset();
49 
50  // Get an upper bound on the best mapping by starting with no lattice equivalence
51  m_N = DMatType::Identity(3, 3);
52  // m_cache -> value of m_inv_count that gives m_N = identity;
53  m_cache = m_V_inv * m_U;
54  m_F = m_L2 * m_cache * m_L1.inverse();
55  //std::cout << "starting m_F is \n" << m_F << " det: " << m_F.determinant() << "\n";
56  double best_cost = _calc_strain_cost();
57  //std::cout << "starting cost is " << m_cost << "\n";
58  //std::cout << "Starting cost is " << m_cost << ", starting N is \n" << m_N << "\nand starting F is \n" << m_F << "\n";
59  //std::cout << "Best_cost progression: " << best_cost;
60  while(next_mapping_better_than(best_cost - m_tol).strain_cost() < best_cost) {
61  best_cost = strain_cost();
62  //std::cout << " " << best_cost;
63  }
64 
65  m_cost = best_cost;
66  return *this;
67  }
68  //*******************************************************************************************
69 
70  const LatticeMap &LatticeMap::next_mapping_better_than(double max_cost) const {
71  m_cost = 1e20;
72  return _next_mapping_better_than(max_cost);
73  }
74  //*******************************************************************************************
75  // Implements the algorithm as above, with generalized inputs:
76  // -- m_inv_count saves the state between calls
77  // -- the search breaks when a mapping is found with cost < max_cost
78  const LatticeMap &LatticeMap::_next_mapping_better_than(double max_cost) const {
79 
80  DMatType init_F(m_F);
81  double tcost = max_cost;
82  for(++m_inv_count; m_inv_count.valid(); ++m_inv_count) {
83  //continue if determinant is not 1, because it doesn't preserve volume
84  if(!almost_equal(std::abs(m_inv_count().determinant()), 1))
85  continue;
86 
87  m_F = m_L2 * m_inv_count().cast<double>() * m_L1.inverse(); // -> F
88  tcost = _calc_strain_cost();
89  if(tcost < max_cost) {
90  m_cost = tcost;
91 
92  // need to undo the effect of transformation to reduced cell on 'N'
93  // Maybe better to get m_N from m_F instead? m_U and m_V_inv depend on the lattice reduction
94  // that was performed in the constructor, so we would need to store "non-reduced" L1 and L2
95  m_N = m_U * m_inv_count().cast<double>().inverse() * m_V_inv;
96  // We already have:
97  // m_F = m_L2 * m_inv_count().cast<double>() * m_L1.inverse();
98  break;
99  }
100  }
101  if(!(tcost < max_cost)) {
102  // If no good mappings were found, uncache the starting value of m_F
103  m_F = init_F;
104  // m_N hasn't changed if tcost>max_cost
105  // m_cost hasn't changed either
106  }
107  // m_N, m_F, and m_cost will describe the best mapping encountered, even if nothing better than max_cost was encountered
108 
109 
110  //std::cout << "Final N is:\n" << N << "\n\nAND final cost is " << min_cost << "\n\n";
111  return *this;
112  }
113 
114  //*******************************************************************************************
115 
116  // strain_cost is the mean-square displacement of a point on the surface of a sphere having volume = relaxed_atomic_vol
117  // when it is deformed by the volume-preserving deformation F_deviatoric = F/det(F)^(1/3)
118  double LatticeMap::calc_strain_cost(const Eigen::Matrix3d &F, double relaxed_atomic_vol) {
119  // -> epsilon=(F_deviatoric-identity)
120  Eigen::Matrix3d cache = 0.5 * (F.transpose() * F / pow(std::abs(F.determinant()), 2.0 / 3.0) - Eigen::Matrix3d::Identity(3, 3));
121 
122  // geometric factor: (3*V/(4*pi))^(2/3)/3 = V^(2/3)/7.795554179
123  return std::pow(std::abs(relaxed_atomic_vol), 2.0 / 3.0) * cache.squaredNorm() / 7.795554179;
124  }
125  //*******************************************************************************************
127  // -> epsilon=(F_deviatoric-identity)
128  m_cache.noalias() = 0.5 * (m_F.transpose() * m_F / (m_scale * m_scale) - Eigen::Matrix3d::Identity(3, 3));
129 
130  // geometric factor: (3*V/(4*pi))^(2/3)/3 = V^(2/3)/7.795554179
131  return std::pow(m_atomic_vol, 2.0 / 3.0) * m_cache.squaredNorm() / 7.795554179;
132  }
133 
134 
135 }
double m_atomic_vol
Definition: LatticeMap.hh:53
Eigen::Matrix< int, 3, 3, Eigen::DontAlign > IMatType
Definition: LatticeMap.hh:29
double _calc_strain_cost() const
Definition: LatticeMap.cc:126
Main CASM namespace.
Definition: complete.cpp:8
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:104
LatticeMap(const Lattice &_ideal, const Lattice &_strained, Index _num_atoms, double _tol, int _range)
Definition: LatticeMap.cc:4
const Eigen::Matrix3d & inv_lat_column_mat() const
Inverse of Lattice::lat_column_mat() It is the transformation matrix 'C2F', such that f = C2F * c whe...
Definition: Lattice.hh:113
double strain_cost() const
Definition: LatticeMap.hh:35
const LatticeMap & best_strain_mapping() const
Definition: LatticeMap.cc:47
EigenIndex Index
For long integer indexing:
DMatType m_cache
Definition: LatticeMap.hh:58
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > inverse(const Eigen::MatrixBase< Derived > &M)
Return the integer inverse matrix of an invertible integer matrix.
const LatticeMap & _next_mapping_better_than(double max_cost) const
Definition: LatticeMap.cc:78
Eigen::Matrix3d Matrix3d
static double calc_strain_cost(const Eigen::Matrix3d &F, double relaxed_atomic_vol)
Definition: LatticeMap.cc:118
Eigen::Matrix< double, 3, 3, Eigen::DontAlign > DMatType
Definition: LatticeMap.hh:28
const LatticeMap & next_mapping_better_than(double max_cost) const
Definition: LatticeMap.cc:70
DMatType m_V_inv
Definition: LatticeMap.hh:51
EigenCounter< IMatType > m_inv_count
Definition: LatticeMap.hh:57
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)