|
"""empirical parameter calculator, includes calculation functions for 14 values: |
|
'Enthalpy(kJ/mol)', 'std_enthalpy(kJ/mol)', 'average_atomic_radius', 'Delta(%)', 'Omega', 'Entropy(J/K*mol)', 'Tm(K)', |
|
'std_Tm (%)', 'X', 'std_X(%)', 'VEC', 'std_VEC', 'Density(g/com^3)', 'Price(USD/kg)' |
|
written by Will Nash and Zhipeng Li |
|
version 2.1.1""" |
|
|
|
import itertools |
|
import numpy as np |
|
|
|
from pip._internal import main |
|
|
|
|
|
main(['install', 'matminer']) |
|
import matminer.utils.data as mm_data |
|
|
|
|
|
|
|
|
|
price_dic = { |
|
"Ag": 462, "Al": 1.91, "Au": 38189, "B": 2386, "Be": 831.6, "Bi": 10.34, "C": 24, "Ca": 5.93, "Cd": 1.98, "Ce": 7, |
|
"Co": 59.5, "Cr": 7.64, "Cu": 5.9, "Dy": 350, "Er": 95, "Fe": 0.08, "Gd": 55, "Ge": 1833, "Hf": 1414, "Ho": 1400, |
|
"In": 341.6, "Ir": 31186, "La": 7, "Li": 115.7, "Lu": 6269, "Mg": 2.26, "Mn": 2.06, "Mo": 16, "Nb": 42, "Nd": 60, |
|
"Ni": 9.19, "Os": 12860, "P": 300, "Pb": 2.29, "Pd": 34401, "Pr": 85, "Pt": 26492, "Re": 1635, "Rh": 76840, |
|
"Ru": 14720, "Sb": 7.05, "Sc": 15000, "Si": 1.91, "Sm": 14.35, "Sn": 20, "Sr": 5.4, "Ta": 238, "Tb": 550, |
|
"Ti": 3.77, "Tm": 6200, "V": 22.6, "W": 25.52, "Y": 35, "Yb": 1600, "Zn": 2.83, "Zr": 23.14, "H": 23.64, |
|
"He": 40.39, "N": 2.77, "O": 0.64, "F": 1900, "Ne": 629.9, "Na": 3.04, "S": 0.1, "Cl": 1.5, "Ar": 2.56, "K": 13.02, |
|
"Ga": 278.2, "As": 1.74, "Se": 30.37, "Br": 4.4, "Kr": 1.4, "Rb": 14720, "Te": 55.68, "I": 28.00, |
|
"Xe": 9.2, "Cs": 73400, "Ba": 550, "Eu": 258, "Hg": 38.44, "Tl": 7400, "Th": 176, "U": 57.76, |
|
} |
|
|
|
|
|
class EmpiricalParams(object): |
|
"""functions for returning the empirical parameters of alloy compositions where element list is a list of pymatgen |
|
Elements that are in the alloy, and mol_ratio is their respective mole ratios """ |
|
|
|
def __init__(self, element_list, mol_ratio=None): |
|
self.element_list = element_list |
|
if mol_ratio is None: |
|
mol_ratio = [1 / len(element_list)] * len(element_list) |
|
self.mol_ratio = np.divide(mol_ratio, np.sum(mol_ratio)) |
|
self.a = self.mean_atomic_radius() |
|
self.delta = self.atomic_size_difference() |
|
self.Tm = self.average_melting_point() |
|
self.mix_entropy = self.entropy_mixing() |
|
self.mix_enthalpy = self.enthalpy_mixing() |
|
self.omega = self.calc_omega() |
|
self.x = self.mean_electronegativity() |
|
self.std_x = self.std_electronegativity() |
|
self.vec = self.average_vec() |
|
self.density = self.calc_density() |
|
self.price = self.calc_price() |
|
|
|
|
|
|
|
self.std_enthalpy = self.std_enthalpy_mixing() |
|
self.std_Tm = self.std_melting_point() |
|
self.vec_std = self.std_vec() |
|
|
|
''' |
|
2. average atomic radius |
|
''' |
|
def mean_atomic_radius(self): |
|
"""function to return the mean atomic size radius 平均原子尺寸半径 (a) of the alloy""" |
|
radii = [] |
|
for i in range(len(self.element_list)): |
|
radii.append(self.element_list[i].atomic_radius) |
|
avg_radii = np.dot(radii, self.mol_ratio) |
|
return avg_radii |
|
|
|
''' |
|
3. atomic size difference |
|
''' |
|
def atomic_size_difference(self): |
|
"""function to return the atomic size difference 原子半径差比率 (delta) of the alloy""" |
|
delta = 0 |
|
radii = [] |
|
for i in range(len(self.element_list)): |
|
radii.append(self.element_list[i].atomic_radius) |
|
|
|
for j in range(len(self.element_list)): |
|
delta += self.mol_ratio[j] * np.square((1 - np.divide(radii[j], self.a))) |
|
|
|
return np.sqrt(delta) |
|
|
|
''' |
|
6. average melting point |
|
''' |
|
def average_melting_point(self): |
|
"""function to return the average melting point 熔点的均值 (Tm) of the alloy""" |
|
Tm = 0 |
|
for i in range(len(self.element_list)): |
|
Tm += self.mol_ratio[i] * self.element_list[i].melting_point |
|
return Tm |
|
|
|
''' |
|
7. standard melting point |
|
''' |
|
def std_melting_point(self): |
|
"""function to return the standard deviation (in percentage) of melting points 熔点的标准偏差 (sigma_t) of the alloy""" |
|
sigma_t = 0 |
|
T = [] |
|
for i in range(len(self.element_list)): |
|
T.append(self.element_list[i].melting_point) |
|
|
|
for j in range(len(self.element_list)): |
|
sigma_t += self.mol_ratio[j] * np.square((1 - np.divide(T[j], self.Tm))) |
|
return np.sqrt(sigma_t) |
|
|
|
''' |
|
1. entropy of mixing |
|
''' |
|
def entropy_mixing(self): |
|
"""function to return entropy of mixing 混合熵 for alloy elements based on Boltzmann's hypothesis""" |
|
entropy = 0 |
|
for i in range(len(self.mol_ratio)): |
|
if self.mol_ratio[i] > 0: |
|
entropy += self.mol_ratio[i] * np.log(self.mol_ratio[i]) |
|
return -8.31446261815324 * entropy |
|
|
|
''' |
|
4. enthalpy of mixing |
|
''' |
|
def enthalpy_mixing(self): |
|
"""function to return the sum enthalpy of mixing 混合焓和 of an alloy system based on binary mixtures and the molar |
|
ratio """ |
|
enthalpies = [] |
|
mol_coefficients = [] |
|
|
|
for pair in itertools.combinations(self.element_list, 2): |
|
enthalpies.append(mm_data.MixingEnthalpy().get_mixing_enthalpy(*pair)) |
|
|
|
for molies in itertools.combinations(self.mol_ratio, 2): |
|
mol_coefficients.append(4 * np.product(molies)) |
|
|
|
enthalpy = np.dot(enthalpies, mol_coefficients) |
|
return enthalpy |
|
|
|
''' |
|
5. standard deviation of enthalpy |
|
''' |
|
def std_enthalpy_mixing(self): |
|
"""function to return the standard deviation of enthalpy of mixing 混合焓的标准偏差 (sigma_h) of the alloy""" |
|
sigma_h = 0 |
|
H = np.zeros((len(self.element_list), len(self.element_list))) |
|
for i in range(len(self.element_list)): |
|
for j in range(len(self.element_list)): |
|
if i != j: |
|
H[i][j] = mm_data.MixingEnthalpy().get_mixing_enthalpy(self.element_list[i], self.element_list[j]) |
|
|
|
for i in range(len(self.element_list)): |
|
for j in range(len(self.element_list)): |
|
if i != j: |
|
sigma_h += self.mol_ratio[i] * self.mol_ratio[j] * np.square(H[i][j] - self.enthalpy_mixing()) |
|
sigma_h = sigma_h / 2 |
|
return np.sqrt(sigma_h) |
|
|
|
''' |
|
12. Omega omega |
|
''' |
|
def calc_omega(self): |
|
"""function to return the omega value of the alloy""" |
|
if np.abs(self.mix_enthalpy) < 1e-6: |
|
self.mix_enthalpy = 1e-6 |
|
return self.Tm * self.mix_entropy / (np.abs(self.mix_enthalpy) * 1000) |
|
|
|
''' |
|
8. average electronegativity |
|
''' |
|
def mean_electronegativity(self): |
|
"""function to return the mean electronegativity 电负性的均值 (x) of the alloy""" |
|
x_list = [] |
|
for i in range(len(self.element_list)): |
|
x_list.append(self.element_list[i].X) |
|
x_avg = np.dot(x_list, self.mol_ratio) |
|
return x_avg |
|
|
|
''' |
|
9. standard deviation of electronegativity |
|
''' |
|
def std_electronegativity(self): |
|
"""function to return the standard deviation (in percentage) of electronegativity 电负性的标准偏差 (sigma_x) of the alloy""" |
|
sigma_x = 0 |
|
x_list = [] |
|
for i in range(len(self.element_list)): |
|
x_list.append(self.element_list[i].X) |
|
|
|
for j in range(len(self.element_list)): |
|
sigma_x += self.mol_ratio[j] * np.square(x_list[j] - self.x) |
|
return np.sqrt(sigma_x) / self.x |
|
|
|
''' |
|
10. valence electron concentration |
|
''' |
|
def num_ve(self, element): |
|
"""function to return the number of valence electron of the element元素的价电子""" |
|
e_structure = element.full_electronic_structure |
|
outer = element.full_electronic_structure[-1][0] |
|
num_e = 0 |
|
for t in e_structure: |
|
if t[0] == outer - 1 and t[1] == 'd': |
|
num_e += t[2] |
|
if t[0] == outer: |
|
num_e += t[2] |
|
return num_e |
|
|
|
''' |
|
average of valence electron concentration |
|
''' |
|
def average_vec(self): |
|
"""function to return the average of valence electron concentration 价电子浓度的均值 (vec) of the alloy""" |
|
vec = 0 |
|
for i in range(len(self.element_list)): |
|
vec += self.mol_ratio[i] * self.num_ve(self.element_list[i]) |
|
return vec |
|
|
|
''' |
|
11. standard deviation of valence electron concentration |
|
''' |
|
def std_vec(self): |
|
"""function to return the standard deviation of valence electron concentration 价电子浓度的标准偏差 (sigma_vec) of the alloy""" |
|
sigma_vec = 0 |
|
vec_list = [] |
|
for i in range(len(self.element_list)): |
|
vec_list.append(self.num_ve(self.element_list[i])) |
|
|
|
for j in range(len(self.element_list)): |
|
sigma_vec += self.mol_ratio[j] * np.square(vec_list[j] - self.vec) |
|
return np.sqrt(sigma_vec) |
|
|
|
''' |
|
average of bulk modulus |
|
''' |
|
def mean_bulk_modulus(self): |
|
"""function to return the average of bulk modulus (k)体积弹性模量 of the alloy""" |
|
k = 0 |
|
for i in range(len(self.element_list)): |
|
if self.element_list[i].bulk_modulus is None: |
|
print(self.element_list[i]) |
|
else: |
|
k += self.mol_ratio[i] * self.element_list[i].bulk_modulus |
|
return k |
|
|
|
''' |
|
standard deviation of bulk modulus |
|
''' |
|
def std_bulk_modulus(self): |
|
"""function to return the standard deviation of bulk modulus (k)体积弹性模量 of the alloy""" |
|
sigma_k = 0 |
|
k_list = [] |
|
for i in range(len(self.element_list)): |
|
k_list.append(self.element_list[i].bulk_modulus) |
|
|
|
for j in range(len(self.element_list)): |
|
if self.element_list[i].bulk_modulus is None: |
|
print(self.element_list[i]) |
|
else: |
|
sigma_k += self.mol_ratio[j] * np.square(k_list[j] - self.k) |
|
return np.sqrt(sigma_k) |
|
|
|
''' |
|
13. density |
|
''' |
|
def calc_density(self): |
|
"""function to return the density (g/cm^3) of the alloy""" |
|
mass = 0 |
|
volume = 0 |
|
for i in range(len(self.element_list)): |
|
mass += float(self.element_list[i].atomic_mass) * self.mol_ratio[i] |
|
volume += self.mol_ratio[i] * self.element_list[i].molar_volume |
|
return mass / volume |
|
|
|
''' |
|
14. price/element cost |
|
''' |
|
def calc_price(self): |
|
"""function to return the price (USD/kg) of the alloy""" |
|
total_mass = 0 |
|
total_price = 0 |
|
for i in range(len(self.element_list)): |
|
if not str(self.element_list[i]) in price_dic: |
|
return 'unknown' |
|
mass = float(self.element_list[i].atomic_mass) * self.mol_ratio[i] |
|
total_mass += mass |
|
total_price += mass * price_dic[str(self.element_list[i])] |
|
return format(total_price / total_mass, '.2f') |
|
|