钙钛矿的容忍因子计算使用的离子半径的反证

@钙钛矿的容忍因子计算使用的离子半径的反证

在这里插入图片描述

钙钛矿稳定性的问题非常重要,但理论上对其深层次的理解却进展缓慢。目前广泛采用的衡量钙钛矿稳定性的容忍因子(tolerance factor,简称t,参见图1)早在1926年由Goldschmidt提出。若是稳定的钙钛矿其容忍因子的范围一般为0.77~1.10之间。
在这里插入图片描述

钙钛矿的A位配位数为12,B位配位数为6,X配位数为6。但是笔者最近发现:由于配位数12的离子半径的数据不全,很多科研工作者都将A配位数6的离子半径充当计算时使用的半径。

本文通过收集已发表的文献钙钛矿的容忍因子(TF)来反证推断论文发表者在计算钙钛矿容忍因子时使用的配位数

1. ABX3为例(X为卤素)

1.1原文献ABX3的化学式与其对应的容忍因子TF

X可以为 F、Cl、Br、I
一共有36个样本(图中只是显示了部分)
在这里插入图片描述

1.2 当选择 A的配位数为12,B为6,X为6的离子半径
当选着 A的配位数为12,B为6,X为6时,笔者计算的结果与文献计算结果对比。
(若数据中缺乏配位数为12 的离子半径,则退而求其次选择配位数为8的离子半径,
若数据中缺乏配位数为8 的离子半径,选择配位数为6的离子半径,
因为选择配位数为6的离子半径的数据基本上都是有的,另外如果不这样做的话,代码会报错。)

在这里插入图片描述
在这里插入图片描述

结果1:rmse为0.0826,相关系数R为0.897,从图上可以看到我预测的结果会稍微偏大一些。

1.3 当选择 A的配位数为6,B为6,X为6的离子半径
当选着 A的配位数为6,B为6,X为6时,笔者计算的结果与文献计算结果对比。

在这里插入图片描述
在这里插入图片描述

结果2:rmse为0.026,相关系数R为0.936,从图上可以看到我预测的结果非常接近文献的结果。

结果发现:A配位数为6的结果的更好一些。

Talk is cheap. Show me the code

import pandas as pd 
import numpy as np 
import re 
pd.options.display.max_rows = 1000 
ChemicalFormula = pd.read_excel(r"化学式ABX3.xlsx")   



# A_B_Series = ChemicalFormula["ChemicalFormula"].apply(lambda x : x.split("O")[0]).apply(lambda x :re.findall("[A-Z][a-z]?\d*\.?\d*",x))     
# A_B_Series = ChemicalFormula["ChemicalFormula"].apply(lambda x : x[:-1]).apply(lambda x : re.split('F*?$',x)[0])\
#                                  .apply(lambda x : re.split('Cl*?$',x)[0]).apply(lambda x : re.split('Br*?$',x)[0])\
#                                 .apply(lambda x :re.findall("[A-Z][a-z]?\d*\.?\d*",x))   
A_B_Series = ChemicalFormula["ChemicalFormula"].apply(lambda x :x[:-1]).apply(lambda x : re.split("[A-Z]?[a-z]?$",x)[0])\
                                               .apply(lambda x :re.findall("[A-Z][a-z]?\d*\.?\d*",x))   


import string
s = string.ascii_lowercase   
def list_dict2(series_list): 
    list_2 = []  
    for sl in series_list :
        if len(sl) <= 2:
            b_dict = dict(zip(sl.split("0") ,["1"]))
            list_2.append(b_dict) 
        else:
            if sl[1] in s:
                b_dict = {sl[:2]:sl[2:]} 
                list_2.append(b_dict)         
            else:
                b_dict = {sl[:1]:sl[1:]}
                list_2.append(b_dict)   
    return list_2 

A_B_Series_trans = A_B_Series.map(list_dict2)  
print(A_B_Series_trans.shape)  
A_B_Series_trans.head(10) 


# list_a = [{'Bi': '1'}, {'Ti': '0.15'}, {'Fe': '0.85'}] 
# list_a = [{'Zn': '1'}, {'Ti': '1'}]     
# list_a = [{'La': '0.75'}, {'Sr': '0.25'}, {'Fe': '1'}]   
# list_a = [{'Ni': '0.7'}, {'Cu': '0.2'},{'Ca': '0.1'},{'La': '0.8'}, {'Sr': '0.2'} ] 
# list_a = [{'La': '0.8'}, {'Sr': '0.2'}, {'Ni': '0.8'}, {'Cu': '0.2'}] 
def transform2(list_a):
#     list_a = [{'La': '0.75'}, {'Sr': '0.25'}, {'Fe': '1'}]   
    sum_ = 0  
    empty_dict = {} 
    res = [] 
    for index,dict_ in  enumerate(list_a):
        value = round(float("".join(dict_.values())) ,10)
        empty_dict.update(dict_)  

        sum_ += value

        if round(sum_,10) == 1.0:
#             print(index)   
            right = list_a[index+1 :]
            empty_dict2 = {} 
            for right_dict in  right:
                empty_dict2.update(right_dict) 
            break 
    res.append(empty_dict)      
    res.append(empty_dict2)   
    return res  

A_B_Series_transform2 = A_B_Series_trans.map(transform2) 
print(A_B_Series_transform2.shape) 
A_B_Series_transform2.head(10) 

from mendeleev import get_table 
df_ = get_table('elements')
# get_table('ionicradii')["atomic_number"] [get_table('ionicradii')["atomic_number"] == 14 ]
# get_table('ionicradii')[get_table('ionicradii')["atomic_number"] == 1]     
df_["symbol"].values 
IR = get_table('ionicradii')    

Elements = df_[["atomic_number","symbol"]].merge(IR,on = "atomic_number",how = "left")         
print(Elements.shape)
drop_index = [89,101,106,115,120,127,131,139,148]  

# Elements[Elements["atomic_number"] == 24] 

## Elements[Elements["atomic_number"] == 24][Elements[Elements["atomic_number"] == 24]["spin"] == "HS"].index
Elements = Elements.drop(drop_index)
Elements.reset_index(drop = True,inplace = True) 
print(Elements.shape) 

# Elements_ = Elements["symbol"].drop_duplicates().reset_index(drop = True)   
# Elements_.to_excel("Elements.xlsx",index = False)   
# list_ = [{'Sr': 1}, {'Ti': '.5', 'Ta': '.2', 'Cr': '.3'}]  

def get_charge_list(list_):
    charges_list = []  
    for length in range(2):
        empty_list = [] 
        list_dict = list_[length]    
        for key in list_dict.keys():
            ele = Elements[Elements.symbol == key]
            charge = tuple((set(ele["charge"])))    
            empty_list.append(charge)  
        # de_duplicated_charge :去重后的电子   
        de_duplicated_charge = set(empty_list[0])  
        
        for i in range(0,len(empty_list)): 
            de_duplicated_charge = de_duplicated_charge.intersection(set(empty_list[i]))      
        charges_list.append(list(de_duplicated_charge) ) 
    return charges_list  

A_B_Series_transform2_get_charge = A_B_Series_transform2.map(get_charge_list) 
print(A_B_Series_transform2_get_charge.shape) 
A_B_Series_transform2_get_charge.head() 

A_B_Series_transform2_get_charge_select = A_B_Series_transform2_get_charge[A_B_Series_transform2_get_charge.apply(lambda x : not [] in x)]                                                                              
print(A_B_Series_transform2_get_charge_select.shape) 
A_B_Series_transform2_get_charge_select.head()  

def get_charge_values(charges_list):
    charge_values = [] 
    for i in charges_list [0]:
         for j in charges_list [1]:
            if i + j == 3:
                charge_values.extend([i,j])     
    return charge_values

get_charge = A_B_Series_transform2_get_charge_select.map(get_charge_values)    
print(get_charge.shape)
get_charge.head() 

get_charge_=  get_charge[get_charge.apply(lambda x : x != [])].apply(lambda x : x[0:2])    

element_charges_df = pd.concat([A_B_Series_transform2,get_charge_],axis=1,join='inner')   
element_charges_df.columns = ["ChemicalFormula_dict","list_charges"]  
print(element_charges_df.shape) 
element_charges_df.reset_index(drop = True,inplace = True) 
element_charges_df.head()   

element_charges_df["ChemicalFormula_A"]  = element_charges_df["ChemicalFormula_dict"].apply(lambda x : x[0]) 
element_charges_df["ChemicalFormula_B"]  = element_charges_df["ChemicalFormula_dict"].apply(lambda x : x[1])  

element_charges_df["charges_A"] = element_charges_df["list_charges"].apply(lambda x: x[0])  
element_charges_df["charges_B"] = element_charges_df["list_charges"].apply(lambda x: x[1])   

X = ChemicalFormula["ChemicalFormula"].apply(lambda x :x[:-1]).apply(lambda x : re.findall("[A-Z]?[a-z]?$",x)[0])  
X.name  = "X" 
element_charges_df = pd.concat([ChemicalFormula,element_charges_df,X],axis=1)    


ionic_radius_A = [] 
for index, dict_a in enumerate(element_charges_df["ChemicalFormula_A"]):
    ionic_radius_rectify_sum_A = 0 
    for key in dict_a.keys():
        key_ = "".join(key)  
        value = float(dict_a[key_]) 
        charges_A = element_charges_df.loc[index,"charges_A"]  
        df_charge = Elements[Elements["symbol"] == key_]   
        df_charge_ = df_charge[df_charge["charge"] == charges_A]   
#         coordination = "".join(["XII" if "XII" in df_charge_["coordination"].values else "VI"])
#         coordination = "".join(["XII" if "XII" in df_charge_["coordination"].values else "VIII" if "VIII" in df_charge_["coordination"].values else "VI"])
        coordination = "VI"  
        ionic_radius = float(df_charge_[df_charge_["coordination"]  == coordination]["ionic_radius"])    

        ionic_radius_rectify = ionic_radius* value 
#         print(ionic_radius_rectify)
        ionic_radius_rectify_sum_A += ionic_radius_rectify  
        ionic_radius_rectify_sum_A = round(ionic_radius_rectify_sum_A,10) 
    ionic_radius_A.append(ionic_radius_rectify_sum_A)   

ionic_radius_B = [] 
for index, dict_b in enumerate(element_charges_df["ChemicalFormula_B"]):
    ionic_radius_rectify_sum_B = 0 
    for key in dict_b.keys():
        key_ = "".join(key)  
        value = float(dict_b[key_]) 
       
        charges_B = element_charges_df.loc[index,"charges_B"]  
        df_charge = Elements[Elements["symbol"] == key_]   
        df_charge_ = df_charge[df_charge["charge"] == charges_B]   
#         coordination = "".join(["XII" if "XII" in df_charge_["coordination"].values else "VI"]) 
#         coordination = "".join(["VIII" if "VIII" in df_charge_["coordination"].values else "VI"]) 
#         coordination = "".join(["XII" if "XII" in df_charge_["coordination"].values else "VIII" if "VIII" in df_charge_["coordination"].values else "VI"]) 
        coordination  = "VI" 
        ionic_radius = float(df_charge_[df_charge_["coordination"]  == coordination]["ionic_radius"])    

        ionic_radius_rectify = ionic_radius* value 
#         print(ionic_radius_rectify) 
        ionic_radius_rectify_sum_B += ionic_radius_rectify  
#         print(ionic_radius_rectify_sum_B) 
        ionic_radius_rectify_sum_B = round(ionic_radius_rectify_sum_B,10) 
    ionic_radius_B.append(ionic_radius_rectify_sum_B)   

element_charges_df = pd.concat([element_charges_df,
                                 pd.Series(ionic_radius_A, name="ionic_radius_A"),
                                 pd.Series(ionic_radius_B, name="ionic_radius_B") ],
                                axis=1)   

# RClBrI = Elements[(Elements["symbol"] == "F") | (Elements["symbol"] == "Cl") | (Elements["symbol"] == "Br") | (Elements["symbol"] == "I")]     
RClBrI = Elements[Elements["symbol"].apply(lambda x : x in  ["F","Cl","Br","I"])]  
RClBrI = RClBrI[(RClBrI["charge"] == -1) & (RClBrI["coordination"] == "VI")]    


X_value = [round(float(RClBrI[RClBrI["symbol"] == x]["ionic_radius"].values),10) for x in ["F","Cl","Br","I"]]    
X_name = [f"{i}" for i in ["F","Cl","Br","I"]]  
transform_X = dict (zip(X_name,X_value)) 
element_charges_df["X_value"] = element_charges_df["X"].map(transform_X)  

TF = ((element_charges_df["ionic_radius_A"] + element_charges_df["X_value"]) / \
      (np.sqrt(2)*(element_charges_df["ionic_radius_B"]+element_charges_df["X_value"]))) 

u = (element_charges_df["ionic_radius_B"]  / element_charges_df["X_value"]) 
element_charges_df_1 = pd.concat([element_charges_df,TF,u],axis=1)   
element_charges_df_1.columns = list(element_charges_df) + ["TF_pred","u"]    


def claer_trans_A(dict_a):
    key = "".join(dict_a.keys())   
    return "XII" in  Elements[Elements["symbol"] == key] ["coordination"].values   

def claer_trans_B(dict_a):
    key = "".join(dict_a.keys())   
    return "VI" in  Elements[Elements["symbol"] == key] ["coordination"].values    

element_charges_df_1 = element_charges_df_1[element_charges_df_1["ChemicalFormula_A"]\
                                            .map(claer_trans_A) * element_charges_df_1["ChemicalFormula_B"] .map(claer_trans_B)]           
element_charges_df_1.reset_index(drop = True,inplace = True) 

from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt 
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.family']='Arial'

df_tf = pd.concat([element_charges_df_1["TF"],element_charges_df_1["TF_pred"]],axis=1) 
df_tf.columns = ["附录上的","我计算的",]  
rmse = np.sqrt(mean_squared_error(df_tf["附录上的"],df_tf["我计算的"]))    

print("rmse:",rmse) 
print(df_tf.corr())   

plt.figure(figsize = (10,6)) 
plt.style.use("seaborn-white") 
plt.scatter(df_tf["附录上的"],df_tf["我计算的"],edgecolors=(0,0,0),s=35)
plt.plot([0.7,1.1],[0.7,1.1],'k--', lw=2)
plt.xlabel("true",fontsize = 20) 
plt.ylabel('pred',fontsize = 20)
plt.show()  

结论: 其实作者还以ABO3钙钛矿、A2BB1C6双钙钛矿为例
分别得出的结果与ABX3一致。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值