Source code for httk.analysis.matsci.phasediagram
#
# The high-throughput toolkit (httk)
# Copyright (C) 2012-2015 Rickard Armiento
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Method from A. R. Akbarzadeh, V. Ozolins, and C. Wolverton
# First-Principles Determination of Multicomponent Hydride Phase Diagrams: Application to the Li-Mg-N-H System+
# http://onlinelibrary.wiley.com/doi/10.1002/adma.200700843/abstract
import sys
from httk.core.geometry import hull_z
from httk.core.httkobject import HttkPluginPlaceholder
from httk.core import FracVector
[docs]class PhaseDiagram(object):
"""
"""
def __init__(self):
self.seen_symbols = {}
self.phases = []
self.other_phases = []
self.energies = []
self.ids = []
self.other_ids = []
self._reset()
def _reset(self):
self._hull_indices = None
self._competing_indices = None
self._hull_competing_indices = None
self._hull_distances = None
self._coordsys = None
self._cache_hull = None
self._cache_overhull = None
self._phase_lines = None
[docs] @classmethod
def create(cls):
return cls()
[docs] def add_phase(self, symbols, counts, id, energy):
"""
Handles energy=None, for a phase we don't know the energy of.
"""
counts = FracVector.use(counts)
phase = {}
# In Python 3 symbols in an iterator, so we should convert it to
# a list.
symbols = list(symbols)
for i in range(len(symbols)):
symbol = symbols[i]
if symbol in phase:
phase[symbol] += counts[i]
else:
phase[symbol] = counts[i]
self.seen_symbols[symbol] = True
if energy is not None:
self.phases += [phase]
self.energies += [energy]
self.ids += [id]
else:
self.other_phases += [phase]
self.other_ids += [id]
# Clear out so things get reevaluated
self._reset()
[docs] def set_hull_data(self, hull_indices, competing_indices, hull_competing_indices,
hull_distances, coord_system, phase_lines):
self._hull_indices = hull_indices
self._competing_indices = competing_indices
self._hull_competing_indices = hull_competing_indices
self._hull_distances = hull_distances
self._coord_system = coord_system
self._phase_lines = phase_lines
@property
def hull_indices(self):
if self._hull_indices is None:
self._hull_indices = self._hull()['hull_indices']
return self._hull_indices
@property
def competing_indices(self):
if self._competing_indices is None:
self._competing_indices = self._hull()['competing_indices']
return self._competing_indices
@property
def hull_competing_indices(self):
if self._hull_competing_indices is None:
self._hull_competing_indices = self._overhull()['competing_indices']
return self._hull_competing_indices
@property
def hull_distances(self):
if self._hull_distances is None:
self._hull_distances = self._hull()['hull_distances']
return self._hull_distances
@property
def coord_system(self):
if self._coordsys is None:
self._coordsys = self.seen_symbols.keys()
return self._coordsys
@property
def phase_lines(self):
# TODO: This does not give all phase lines, add code!
if self._phase_lines is None:
hull_points = self.hull_indices
closest = self.hull_competing_indices
lines = {}
for i in range(len(hull_points)):
for j in closest[i]:
lines[(i, j)] = True
self._phase_lines = lines.keys()
return self._phase_lines
def _hull(self):
if self._cache_hull is None:
sys.stderr.write("Warning: calculating convex hull, this may take some time.\n")
symbols = self.coord_system
phaselist = []
for phase in self.phases:
phaselist += [[phase[symbol] if symbol in phase else 0 for symbol in symbols]]
self._cache_hull = hull_z(phaselist, self.energies)
return self._cache_hull
def _overhull(self):
if self._cache_overhull is None:
hull_phases = [self.phases[x] for x in self.hull_indices]
energies = [self.energies[x] for x in self.hull_indices]
sys.stderr.write("Warning: calculating convex hull, this may take some time.\n")
symbols = self.coord_system
phaselist = []
for phase in hull_phases:
phaselist += [[phase[symbol] if symbol in phase else 0 for symbol in symbols]]
self._cache_overhull = hull_z(phaselist, energies)
return self._cache_overhull
[docs] def hull_points(self):
return [self.phases[x] for x in self.hull_indices], [self.ids[x] for x in self.hull_indices]
[docs] def hull_competing_phase_lines(self):
hull_points = self.hull_indices
closest = self.hull_competing_indices
lines = {}
for i in range(len(hull_points)):
for j in closest[i]:
lines[(i, j)] = True
return lines.keys()
[docs] def hull_to_interior_competing_phase_lines(self):
hull_points = self.hull_indicies
closest = self.hull_competing_indices
lines = {}
for i in range(len(hull_points)):
point = hull_points[i]
for point2 in closest[point]:
lines[(point, point2)] = True
return lines.keys()
[docs] def interior_competing_phase_lines(self):
all_points = range(len(self.phases))
hull_points = self.hull_indices
closest = self.competing_indices
lines = {}
for i in range(len(all_points)):
if i in hull_points:
continue
for j in closest[i]:
lines[(i, j)] = True
return lines.keys()
# closest = self.hull['closest_points']
# hull_points = self.hull['hull_points']
# lines = {}
# for i in range(len(hull_points)):
# point = hull_points[i]
# points_to_check = closest[point]
# done_points = []
# while len(points_to_check)>0:
# point2 = points_to_check.pop()
# print("CHECKING:",point2)
# if point2 == point:
# continue
# if point2 in done_points:
# continue
# if point2 in hull_points:
# j = hull_points.index(point2)
# l1 = (i,j)
# l2 = (j,i)
# if not (l1 in lines or l2 in lines):
# lines[l1]=True
# else:
# done_points += [point2]
# points_to_check += closest[point2]
# return lines.keys()
[docs] def hull_point_coords(self):
coordsys = self.coord_system
phases = [self.phases[x] for x in self.hull_indices]
ids = [self.ids[x] for x in self.hull_indices]
phasecoords = []
for phase in phases:
tot = sum([phase[symbol] for symbol in phase])
phasecoords += [[phase[symbol]/tot if symbol in phase else 0 for symbol in coordsys]]
return phasecoords, ids
[docs] def interior_point_coords(self):
coordsys = self.coord_system
phases = self.phases
ids = self.ids
phasecoords = []
for i in range(len(phases)):
if not i in self.hull_indices:
phase = phases[i]
tot = sum([phase[symbol] for symbol in phase])
phasecoords += [[phase[symbol]/tot if symbol in phase else 0 for symbol in coordsys]]
return phasecoords, ids
[docs] def other_point_coords(self):
coordsys = self.coord_system
phases = self.other_phases
ids = self.other_ids
phasecoords = []
for phase in phases:
tot = sum([phase[symbol] for symbol in phase])
phasecoords += [[phase[symbol]/tot if symbol in phase else 0 for symbol in coordsys]]
return phasecoords, ids
[docs] def coords(self):
coordsys = self.coord_system
phases = self.phases
ids = self.ids
phasecoords = []
for phase in phases:
tot = sum([phase[symbol] for symbol in phase])
phasecoords += [[phase[symbol]/tot if symbol in phase else 0 for symbol in coordsys]]
return phasecoords, ids
[docs] def line_coords(self):
phasecoords, ids = self.point_coords()
lines = self.hull_lines()
linecoords = []
for line in lines:
linecoords += [[phasecoords[line[0]], phasecoords[line[1]]]]
return linecoords
vis = HttkPluginPlaceholder("import httk.analysis.matsci.vis")