初次提交

This commit is contained in:
lzy
2025-05-09 14:16:33 +08:00
commit 3a50afeec4
56 changed files with 9224 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import os
from typing import List
from mp_api.client import MPRester
from ...core.config import material_config
async def get_mpid_from_formula(formula: str) -> List[str]:
"""
Get material IDs (mpid) from Materials Project database by chemical formula.
Returns mpids for the lowest energy structures.
Args:
formula: Chemical formula (e.g., "Fe2O3")
Returns:
List of material IDs
"""
os.environ['HTTP_PROXY'] = material_config.HTTP_PROXY or ''
os.environ['HTTPS_PROXY'] =material_config.HTTPS_PROXY or ''
try:
id_list = []
cleaned_formula = formula.replace(" ", "").replace("\n", "").replace("\'", "").replace("\"", "")
if "=" in cleaned_formula:
name, id = cleaned_formula.split("=")
else:
id = cleaned_formula
formula_list = [id]
with MPRester(material_config.MP_API_KEY) as mpr:
docs = mpr.materials.summary.search(formula=formula_list)
if not docs:
return "No materials found"
else:
for doc in docs:
id_list.append(doc.material_id)
return id_list
except Exception as e:
return f"Error: get_mpid_from_formula: {str(e)}"

View File

@@ -0,0 +1,168 @@
import glob
import json
from typing import Dict, Any, Union
from ...core.llm_tools import llm_tool
from .get_mp_id import get_mpid_from_formula
from ..support.utils import extract_cif_info, remove_symmetry_equiv_xyz
from ...core.config import material_config
from pymatgen.core import Structure
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from pymatgen.io.cif import CifWriter
@llm_tool(name="search_crystal_structures_from_materials_project",
description="Retrieve and optimize crystal structures from Materials Project database using a chemical formula")
async def search_crystal_structures_from_materials_project(
formula: str,
conventional_unit_cell: bool = True,
symprec: float = 0.1
) -> str:
"""
Retrieves crystal structures for a given chemical formula from Materials Project database and applies symmetry optimization.
Args:
formula: Chemical formula to search for (e.g., "Fe2O3")
conventional_unit_cell: If True, returns conventional unit cell; if False, returns primitive cell
symprec: Symmetry precision parameter for structure refinement (default: 0.1)
Returns:
Formatted CIF data for the retrieved crystal structures with symmetry analysis
"""
try:
structures = {}
mp_id_list = await get_mpid_from_formula(formula=formula)
if isinstance(mp_id_list, str):
return mp_id_list # 直接返回错误信息
for i, mp_id in enumerate(mp_id_list):
try:
# 文件操作可能引发异常
cif_files = glob.glob(material_config.LOCAL_MP_CIF_ROOT + f"/{mp_id}.cif")
if not cif_files:
continue # 如果没有找到文件跳过这个mp_id
cif_file = cif_files[0]
structure = Structure.from_file(cif_file)
# 结构处理可能引发异常
if conventional_unit_cell:
structure = SpacegroupAnalyzer(structure).get_conventional_standard_structure()
# 对结构进行对称化处理
sga = SpacegroupAnalyzer(structure, symprec=symprec)
symmetrized_structure = sga.get_refined_structure()
# 使用CifWriter生成CIF数据
cif_writer = CifWriter(symmetrized_structure, symprec=symprec, refine_struct=True)
cif_data = str(cif_writer)
# 删除CIF文件中的对称性操作部分
cif_data = remove_symmetry_equiv_xyz(cif_data)
cif_data = cif_data.replace('# generated using pymatgen', "")
# 生成一个唯一的键
formula_key = structure.composition.reduced_formula
key = f"{formula_key}_{i}"
structures[key] = cif_data
# 只保留前config.MP_TOPK个结果
if len(structures) >= material_config.MP_TOPK:
break
except (FileNotFoundError, IndexError) as file_error:
# 处理文件相关错误
continue # 跳过这个mp_id继续处理下一个
except ValueError as value_error:
# 处理结构处理中的值错误
continue # 跳过这个mp_id继续处理下一个
except Exception as process_error:
# 记录处理特定结构时的错误,但继续处理其他结构
print(f"Error processing structure {mp_id}: {str(process_error)}")
continue
# 如果没有成功处理任何结构
if not structures:
return f"No valid crystal structures found for formula: {formula}"
# 格式化结果为可读字符串
prompt = f"""
# Materials Project Symmetrized Crystal Structure Data
Below are symmetrized crystal structure data for {len(structures)} materials from the Materials Project database, in CIF (Crystallographic Information File) format.
These structures have been analyzed and optimized for symmetry using SpacegroupAnalyzer with precision parameter symprec={symprec}.\n
"""
for i, (key, cif_data) in enumerate(structures.items(), 1):
prompt += f"[cif {i} begin]\n"
prompt += cif_data
prompt += f"\n[cif {i} end]\n\n"
return prompt
except Exception as e:
# 捕获整个函数执行过程中的任何未处理异常
return f"Error: An unexpected error occurred while processing crystal structures: {str(e)}"
@llm_tool(name="search_material_property_from_material_project",
description="Query material properties from Materials Project database using chemical formula")
async def search_material_property_from_materials_project(
formula: str,
) -> str:
"""
Retrieve detailed property data for materials matching a chemical formula from Materials Project database.
Args:
formula: Chemical formula of the material(s) to search for (e.g. 'Fe2O3', 'LiFePO4')
Returns:
Formatted string containing material properties including structure, electronic, thermodynamic and mechanical data
"""
# 获取MP ID列表
mp_id_list = await get_mpid_from_formula(formula=formula)
# 检查get_mpid_from_formula的返回值类型
# 如果返回的是字符串,说明发生了错误或没有找到材料
if isinstance(mp_id_list, str):
return mp_id_list # 直接返回错误信息
# 如果代码执行到这里说明mp_id_list是一个有效的ID列表
try:
# 获取材料属性
properties = []
for mp_id in mp_id_list:
try:
file_path = material_config.LOCAL_MP_PROPS_ROOT + f"/{mp_id}.json"
crystal_props = extract_cif_info(file_path, ['all_fields'])
properties.append(crystal_props)
except Exception as file_error:
# 记录单个文件处理错误但继续处理其他ID
continue
# 检查是否有结果
if len(properties) == 0:
return "No material properties found for the given formula, please try again."
# 只保留前MP_TOPK个结果
properties = properties[:material_config.MP_TOPK]
# 格式化结果
formatted_results = []
for i, item in enumerate(properties, 1):
formatted_result = f"[property {i} begin]\n"
formatted_result += json.dumps(item, indent=2)
formatted_result += f"\n[property {i} end]\n\n"
formatted_results.append(formatted_result)
# 将所有结果合并为一个字符串
res_chunk = "\n\n".join(formatted_results)
res_template = f"""
Here are the search material property from the Materials Project database:
Due to length limitations, only the top {len(properties)} results are shown below:\n
{res_chunk}
"""
return res_template
except Exception as e:
return f"Error: processing material properties: {str(e)}"