基于统计概率的机器学习,模型离不开大量的数据,在材料学中,这些数据可以是材料结构或是材料的性质。结构决定性质,因此无论是从结构预测出性质,还是从性质反推出结构,都离不开大量的数据。为此,这方面,Materials Project等大量材料数据库被建立。 这里,我们将学习到如何从这些数据库中拉取我们想要获取的材料数据,本文以钙钛矿晶体结构为例,拉取MP数据库中的钙钛矿以及类钙钛矿的材料数据。
在下面的例子中,不仅能够学习到如何构建数据库,还能够学习或巩固python的用法或技巧。
在python中 # 以及'''XXX'''代表了注释,python脚本在编译运行的过程中会自动跳过这些内容,这些内容都是我在学习过程中,帮助我理解和整理思路时的笔记,希望对你也有所帮助。
导入包以及常量
from mp_api.client import MPResterimport csvfrom tqdm import tqdm#https://next-gen.materialsproject.org/api 注册获得API_KEYAPI_KEY = "APIKEY"OUTPUT_FILE = "perovskite_dataset.csv"通过API调用MP数据库,拉取Description中含有perovskite 字段的结构。
mpr.materials.robocrys.search(keywords=["perovskite"]
这是MPRester包中的固定写法,使用时,仅需要更换关键词即可搜索其他的材料结构。
def get_robo_perovskites(mpr): docs = mpr.materials.robocrys.search(keywords=["perovskite"])''' 等价写法:用set可以避免重复统计 rob_ids() for doc in docs: rob_ids.add(doc.material_id) '''return set(doc.material_id for doc in docs)拉取Tags标签或remarks标记中含有perovskite 字段的结构。
#材料ID,标签,备注信息def get_tag_perovskites(mpr):'''如返回信息:MPDataDoc<ProvenanceDoc>(material_id=MPID(mp-1244953),remarks=['Amorphous'], ->表明非晶体tags=['Amorphous'],fields_not_requested=['builder_meta', 'nsites', 'elements', 'nelements', 'composition', 'composition_reduced', 'formula_pretty', 'formula_anonymous', 'chemsys', 'volume', 'density', 'density_atomic', 'symmetry', 'deprecated', 'deprecation_reasons', 'last_updated', 'origins', 'warnings', 'structure', 'property_name', 'created_at', 'references', 'authors', 'theoretical', 'database_IDs', 'history'])]''' docs = mpr.materials.provenance.search( fields=["material_id", "tags", "remarks"] ) ids = []for doc in docs:''' 取"tags"字段,如果没有,则返回[] 等价于 if "tags" in doc: tags=doc["tags"] else: tags=[] or []防止key不存在,直接返回[] ''' tags = doc.get("tags", []) or [] remarks = doc.get("remarks", []) or []''' tags + remarks:拼接列表 等价为: for x in (tags+remarks): #str(x).lower():将xstring化,小写化 if "perovskite" in str(x).lower(): ids.append(doc.get("material_id")) return False '''if any("perovskite" in str(x).lower() for x in (tags + remarks)): ids.append(doc.get("material_id"))return set(ids)获取结构性质
def fetch_summary(mpr, material_ids): results = [] batch_size = 1000 ids_list = list(material_ids)''' range(0,len(ids_list),batch_size):从0开始,ids_list的长度结束,步长为batch_size tqdm():进度条工具表 '''for i in tqdm(range(0, len(ids_list), batch_size)):#batch_ids:每一次取1000个数据 batch_ids = ids_list[i:i + batch_size] docs = mpr.materials.summary.search( material_ids=batch_ids, fields=["material_id","formula_pretty",#结构表达式"energy_above_hull",#凸包能"formation_energy_per_atom",#形成能"band_gap","density","volume","nsites"#晶胞内的原子数 ] ) results.extend(docs)return results存入csv文件
import pandas as pdrows = []def save_to_csv(data, filename):print("Saving to CSV...") df=pd.DataFrame([ {"material_id": d.material_id,"formula": d.formula_pretty,"energy_above_hull": d.energy_above_hull,"formation_energy": d.formation_energy_per_atom,"band_gap": d.band_gap,"density": d.density,"volume": d.volume,"nsites": d.nsites }for d in data ]) df.to_csv(filename,index=True,encoding="utf-8")print("CSV saved!")主函数调用所有方法
def main():with MPRester(API_KEY) as mpr: robo_ids=get_robo_perovskite(mpr) tags_ids=get_tag_perovskite(mpr)#取并集 all_ids=robo_ids|tags_idsprint(f"Total perovskites:{len(all_ids)}") data=fetch_summary(mpr,all_ids) save_to_csv(data,OUTPUT_FILENAME)