CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
Hull.cc
Go to the documentation of this file.
1 #include "casm/hull/Hull.hh"
2 
3 #include <iterator>
4 
5 #include "casm/clex/PrimClex.hh"
6 #include "casm/misc/PCA.hh"
7 #include "casm/external/Eigen/Dense"
8 #include "casm/external/qhull/libqhullcpp/QhullFacetList.h"
9 #include "casm/external/qhull/libqhullcpp/QhullVertexSet.h"
12 
13 namespace CASM {
14 
15  namespace Hull_impl {
16 
18  void _validate_input(const ConstConfigSelection &selection,
19  const Hull::CompCalculator &comp_calculator,
20  const Hull::EnergyCalculator &energy_calculator);
21  }
22 
23 
25  Hull::Hull(const ConstConfigSelection &_selection,
26  const CompCalculator &_comp_calculator,
27  const EnergyCalculator &_energy_calculator,
28  double _singular_value_tol,
29  double _bottom_facet_tol) :
30  m_selection(_selection),
31  m_comp_calculator(_comp_calculator),
32  m_energy_calculator(_energy_calculator) {
33 
35 
36  // get the number of configurations and compositions (full composition space)
39 
40  // generate initial set of points (col vector matrix)
41  Eigen::MatrixXd mat(Ncomp + 1, Nselected);
42 
43  Index i = 0;
44  for(auto it = m_selection.selected_config_begin(); it != m_selection.selected_config_end(); ++it) {
45  mat.block(0, i, Ncomp, 1) = composition(*it);
46  mat(Ncomp, i) = energy(*it);
47  ++i;
48  }
49 
50  // principal component analysis to get rotation matrix
51  PCA pca(mat.topRows(Ncomp), _singular_value_tol);
52  m_reduce = pad(pca.reduce(), 1);
53 
54  Eigen::MatrixXd reduced_mat = m_reduce * mat;
55 
56  // Construct Qhull PointCoordiantes, with correct dimension
57  orgQhull::PointCoordinates points(reduced_mat.rows(), "");
58 
59  // use matrix data to set point coordinates
60  points.append(reduced_mat.size(), reduced_mat.data());
61 
62  // calculate hull
63  std::string qh_command = "";
64  m_hull.runQhull(points.comment().c_str(), points.dimension(), points.count(), &*points.coordinates(), qh_command.c_str());
65 
66  // check for errors
67  if(m_hull.hasQhullMessage()) {
68  std::cerr << "\nQhull message:\n" << m_hull.qhullMessage();
69  m_hull.clearQhullMessage();
70  throw std::runtime_error("Qhull Error (see message)");
71  }
72 
73  // want to find minimum distance from point to a bottom facet
74 
75  // V: any vector from point to facet
76  // N: outward unit normal of facet
77  // D: unit 'down' direction (by convention always [0, 0, ..., -1])
78  //
79  // distance to facet along normal: V.dot(N) = a (Qhull reports this as a negative number)
80  // proj of D onto N: D.dot(N) = b (if b is positive, then this is 'bottom' facet)
81  // distance along D to facet: a/b
82 
83  // collect bottom facets (along with 'b')
84  {
85  auto begin = m_hull.facetList().begin();
86  auto end = m_hull.facetList().end();
87  int dim = m_hull.dimension();
88  double b;
89  Eigen::Map<const Eigen::VectorXd> outnorm((*begin).hyperplane().begin(), dim);
90 
91  for(auto facet_it = begin; facet_it != end; ++facet_it) {
92 
93  // reset location of outnorm data
94  new(&outnorm) Eigen::Map<const Eigen::VectorXd>((*facet_it).hyperplane().begin(), dim);
95  b = -outnorm(dim - 1);
96 
97  if(b > _bottom_facet_tol) {
98  m_bottom_facets.push_back(std::make_pair(*facet_it, b));
99  }
100  }
101  }
102 
103 
104  // find set of bottom vertices using bottom facets
105  // use pointers for the set comparison
106  for(auto facet_it = m_bottom_facets.begin(); facet_it != m_bottom_facets.end(); ++facet_it) {
107  orgQhull::QhullVertexSet vertices = (*facet_it).first.vertices();
108  for(auto vertex_it = vertices.begin(); vertex_it != vertices.end(); ++vertex_it) {
109  m_bottom_vertices.insert(*vertex_it);
110  }
111  }
112 
113  }
114 
116  const orgQhull::Qhull &Hull::data() const {
117  return m_hull;
118  }
119 
125  const Eigen::MatrixXd &Hull::reduce() const {
126  return m_reduce;
127  }
128 
130  const Eigen::Transpose<const Eigen::MatrixXd> Hull::expand() const {
131  return m_reduce.transpose();
132  }
133 
135  const Configuration &Hull::configuration(const orgQhull::QhullPoint &point) const {
137  std::advance(it, point.id());
138  return *it;
139  }
140 
142  const Configuration &Hull::configuration(const orgQhull::QhullVertex &vertex) const {
143  return configuration(vertex.point());
144  }
145 
149  Eigen::VectorXd Hull::mu(const orgQhull::QhullFacet facet) const {
150 
151  // mu_i = dG/dx_i
152  // hyperplane normal = [dx_i, dx_j, ... dG] (normalized)
153 
154  int dim = m_hull.dimension();
155  Eigen::Map<const Eigen::VectorXd> reduced_hyperplane(facet.hyperplane().begin(), dim);
156 
157  Eigen::VectorXd _mu = Eigen::VectorXd::Constant(dim - 1, reduced_hyperplane(dim - 1));
158 
159  return _mu.cwiseQuotient(expand().leftCols(dim - 1) * reduced_hyperplane.head(dim - 1));
160  }
161 
166 
167  // mu_i = dG/dx_i
168  // hyperplane normal = [dx_i, dx_j, ... dG] (normalized)
169 
170 
171  // normal vector to hyperplane
172  Eigen::VectorXd hyperplane(mu.size() + 1);
173  hyperplane.head(mu.size()) = mu.cwiseInverse();
174  hyperplane(mu.size()) = 1.0;
175  hyperplane.normalize();
176 
177  Eigen::VectorXd reduced_hyperplane = reduce() * hyperplane;
178 
179  double max_offset = std::numeric_limits<double>::min();
180  orgQhull::QhullVertex _groundstate = *m_bottom_vertices.begin();
181 
182  // m_bottom_vertices: a std::set<orgQhull::QhullVertex*>
183  for(auto it = m_bottom_vertices.begin(); it != m_bottom_vertices.end(); ++it) {
184 
185  Eigen::Map<const Eigen::VectorXd> reduced_vertex_point(it->point().begin(), it->point().size());
186 
187  double offset = reduced_hyperplane.dot(reduced_vertex_point);
188 
189  if(offset > max_offset) {
190  max_offset = offset;
191  _groundstate = *it;
192  }
193  }
194 
195  return configuration(_groundstate);
196  }
197 
199  double Hull::energy(const Configuration &config) const {
200  return (*m_energy_calculator)(config);
201  }
202 
205  return (*m_comp_calculator)(config);
206  }
207 
208 
211  Eigen::VectorXd _point(m_reduce.cols());
212  _point.head(m_reduce.cols() - 1) = composition(config);
213  _point.tail(1)(0) = energy(config);
214  return _point;
215  }
216 
219  return reduce() * point(config);
220  }
221 
223  double Hull::dist_to_hull(const Configuration &config) const {
224  return dist_to_hull(reduced_point(config));
225  }
226 
228  double Hull::dist_to_hull(Eigen::VectorXd _reduced_point) const {
229 
230  // want to find minimum distance from point to a bottom facet
231 
232  // V: any vector from point to facet
233  // N: outward unit normal of facet
234  // D: unit 'down' direction (by convention always [0, 0, ..., -1])
235  //
236  // distance to facet along normal: V.dot(N) = a (Qhull reports this as a negative number)
237  // proj of D onto N: D.dot(N) = b (if b is positive, then this is 'bottom' facet)
238  // distance along D to facet: a/b
239 
240  orgQhull::QhullPoint qpoint(_reduced_point.size(), _reduced_point.data());
241 
242  double a, b;
244 
245  for(auto facet_it = m_bottom_facets.begin(); facet_it != m_bottom_facets.end(); ++facet_it) {
246 
247  // Qhull distance is negative for internal points
248  a = -(facet_it->first).distance(qpoint);
249  b = facet_it->second;
250  if(a / b < dist_to_hull) {
251  dist_to_hull = a / b;
252  }
253  }
254 
255  return dist_to_hull;
256  }
257 
258  namespace Hull_impl {
259 
261  void _validate_input(const ConstConfigSelection &selection,
262  const Hull::CompCalculator &comp_calculator,
263  const Hull::EnergyCalculator &energy_calculator) {
264 
265  typedef std::map<std::string, std::pair<bool, bool> > CheckMap;
266 
267  CheckMap invalid_data;
268  for(auto it = selection.selected_config_cbegin(); it != selection.selected_config_cend(); ++it) {
269  if(!comp_calculator.validate(*it) || !energy_calculator.validate(*it)) {
270  invalid_data[it.name()] = std::make_pair(comp_calculator.validate(*it), energy_calculator.validate(*it));
271  }
272  }
273 
274  if(invalid_data.size()) {
275  std::cerr << "Invalid data for hull construction:\n";
277 
279  Formatter("configname", "", [](CheckMap::value_type v) {
280  return v.first;
281  }),
282  Formatter("composition", "", [](CheckMap::value_type v) {
283  return v.second.first ? "OK" : "invalid";
284  }),
285  Formatter("energy", "", [](CheckMap::value_type v) {
286  return v.second.second ? "OK" : "invalid";
287  })
288  );
289 
290  std::cerr << f(invalid_data.begin(), invalid_data.end()) << "\n";
291 
292  std::stringstream ss;
293  ss << "Error in Hull(): Invalid composition or energy data. \n"
294  "Make sure you have set composition axes, all selected configurations\n"
295  "have calculation results, and you have set your chemical reference.";
296  throw std::runtime_error(ss.str());
297  }
298  }
299 
300  }
301 
302 
303 }
304 
305 
Eigen::MatrixXd MatrixXd
Eigen::MatrixXd pad(const Eigen::MatrixXd &M, int n)
Construct a matrix consisting of blocks M and Identity(n,n)
Definition: PCA.hh:88
const_iterator selected_config_cbegin() const
double dist_to_hull(const Configuration &config) const
The distance a Configuration is above the hull along the energy axis.
Definition: Hull.cc:223
Abstract base class for creating 1D DatumFormatter.
Eigen::VectorXd composition(const Configuration &config) const
Use the CompCalculator to return the composition of a Configuration.
Definition: Hull.cc:204
iterator selected_config_begin()
const orgQhull::Qhull & data() const
const Access the hull object directly
Definition: Hull.cc:116
notstd::cloneable_ptr< CompCalculator > m_comp_calculator
Definition: Hull.hh:89
std::vector< std::pair< orgQhull::QhullFacet, double > > m_bottom_facets
Definition: Hull.hh:98
const Configuration & configuration(const orgQhull::QhullPoint &point) const
Return the configuration corresponding to any point.
Definition: Hull.cc:135
Main CASM namespace.
Definition: complete.cpp:8
Base class for creating scalar DatumFormatter.
Eigen::MatrixXd m_reduce
Definition: Hull.hh:95
Eigen::VectorXd mu(const orgQhull::QhullFacet facet) const
Return the chemical potential corresponding to a facet.
Definition: Hull.cc:149
Hull(const ConstConfigSelection &_selection, const CompCalculator &_comp_calculator=ConfigIO::SpeciesFrac(), const EnergyCalculator &_energy_calculator=ConfigIO::formation_energy_per_species(), double _singular_value_tol=1e-14, double _bottom_facet_tol=1e-14)
Constructor for convex hull in composition/energy space.
Definition: Hull.cc:25
Principle component analysis.
Definition: PCA.hh:9
EigenIndex Index
For long integer indexing:
std::set< orgQhull::QhullVertex, CompareVertex > m_bottom_vertices
Definition: Hull.hh:101
double energy(const Configuration &config) const
Use the EnergyCalculator to return the energy of a Configuration.
Definition: Hull.cc:199
Eigen::VectorXd VectorXd
const_iterator selected_config_cend() const
T max(const T &A, const T &B)
Definition: CASM_math.hh:32
T min(const T &A, const T &B)
Definition: CASM_math.hh:25
orgQhull::Qhull m_hull
Definition: Hull.hh:83
const Eigen::MatrixXd & reduce() const
Orthogonal transformation matrix from a point in full comp/energy space to dimension-reduced comp/ene...
Definition: Hull.cc:125
virtual bool validate(const DataObject &_data_obj) const
Returns true if _data_obj has valid values for requested data.
Extract data from objects of 'DataObject' class.
const Eigen::Transpose< const Eigen::MatrixXd > expand() const
Orthogonal transformation matrix from a point in the dimension-reduced comp/energy space to the full ...
Definition: Hull.cc:130
Eigen::VectorXd reduced_point(const Configuration &config) const
Return a vector corresponding to the coordinate of a given configuration in the reduced composition/e...
Definition: Hull.cc:218
Eigen::VectorXd point(const Configuration &config) const
Return a vector corresponding to the coordinate of a given configuration in full composition/energy s...
Definition: Hull.cc:210
notstd::cloneable_ptr< EnergyCalculator > m_energy_calculator
Definition: Hull.hh:92
ConstConfigSelection m_selection
Definition: Hull.hh:86
const Configuration & groundstate(const Eigen::VectorXd &mu) const
Return the 0K ground state corresponding to the input chemical potential.
Definition: Hull.cc:165
A DatumFormatter that returns a value of specified type, via functions that may be specified at runti...
A Configuration represents the values of all degrees of freedom in a Supercell.
void _validate_input(const ConstConfigSelection &selection, const Hull::CompCalculator &comp_calculator, const Hull::EnergyCalculator &energy_calculator)
Print informational message and throw exception if input data is not valid.
Definition: Hull.cc:261