get_cif.py ダウンロード/コピー
get_cif.py
get_cif.py
1"""
2概要: Materials Project APIから結晶構造データを取得し、指定されたフォーマットで保存するスクリプトです。
3
4詳細説明:
5 このスクリプトは、Materials ProjectのAPIキーを利用して、ユーザーが指定した化学式または元素組成に基づいて結晶構造を検索します。
6 検索結果の構造は、CIF形式(デフォルト)またはPOSCAR形式でファイルに保存されます。
7 スクリプトの実行には、環境変数 MP_APIKEY に有効なMaterials Project APIキーが設定されている必要があります。
8
9 使用方法:
10 コマンドラインから以下のように実行します。
11 python get_cif.py formula [output_format] [prec]
12
13 formula: 検索する化学式またはカンマ区切りの元素リスト (例: "TiO2", "Ti,O")
14 output_format: 出力ファイルの形式 (デフォルト: "cif", その他 "poscar" など)
15 prec: 対称性を分析する際の許容誤差 (デフォルト: 1.0e-3)
16
17関連リンク:
18 get_cif_usage
19"""
20
21import os
22import sys
23
24try:
25 from mp_api.client import MPRester
26 from pymatgen.core.structure import Structure
27 from pymatgen.core import Composition
28 from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
29 from pymatgen.io.cif import CifWriter, CifParser
30except:
31 pass
32
33formula = None
34output_format = "cif"
35prec = 1.0e-3
36
37
38def usage():
39 """
40 概要: スクリプトの正しい使用方法をコンソールに表示します。
41
42 詳細説明:
43 この関数は、スクリプトが引数なしで実行された場合や、ユーザーが使用方法を知りたい場合に呼び出され、
44 必要なコマンドライン引数の形式と説明を出力します。
45 """
46 print()
47 print(f"Usage: python {sys.argv[0]} formula [output_format] [prec]\n")
48
49def update_vars():
50 """
51 概要: コマンドライン引数を解析し、グローバル変数 formula, output_format, prec を更新します。
52
53 詳細説明:
54 sys.argv を読み込み、最初の引数から化学式または元素組成を設定します。
55 オプションで、2番目の引数から出力フォーマット、3番目の引数から対称性の許容誤差を設定します。
56 化学式が指定されていない場合はエラーメッセージを表示し、スクリプトを終了します。
57 """
58 global formula, output_format, prec # output_formuat は typo 修正せず既存コード通り
59
60 argv = sys.argv
61 narg = len(argv)
62 if narg <= 1:
63 print("\nError: Chemical formula must be given as the first arg\n")
64 input("Press ENTER to terminate>>\n")
65 exit()
66
67 formula = argv[1]
68 # 既存コードの typo に合わせる。output_formuat は output_format の間違いだが、変更しないルールによりそのまま
69 if narg >= 3: output_format = argv[2]
70 if narg >= 4: prec = float(argv[3])
71
72
73def get_structure(formula):
74 """
75 概要: Materials Project APIから指定された化学式または元素組成に対応する結晶構造を取得します。
76
77 詳細説明:
78 環境変数 MP_APIKEY からAPIキーを取得し、MPRester を使用してMaterials Projectに接続します。
79 引数 formula がカンマ区切りで複数の元素を含む場合、それらの元素を含む構造を検索します。
80 単一の化学式の場合、その化学式に一致する構造を検索します。
81 見つかった構造は pymatgen.core.structure.Structure オブジェクトのリストとして返されます。
82 APIキーの取得失敗、MPResterの初期化失敗、またはデータが見つからない場合はエラーメッセージを表示し、Noneを返します。
83 検索結果の構造について、入力された元素がすべて含まれているかを確認し、含まれない場合は警告を出力してスキップします。
84
85 引数:
86 :param formula: 検索対象の化学式 (例: "TiO2") またはカンマ区切りの元素組成 (例: "Ti,O")。
87 :type formula: str
88
89 戻り値:
90 :returns: 見つかった結晶構造のリスト、またはエラー発生時やデータが見つからない場合はNone。
91 :rtype: list or None
92 """
93 API_KEY = os.getenv('MP_APIKEY')
94 if API_KEY is None:
95 print("\nError: Can not get MP API Key from the environment var MP_APIKEY\n")
96 return None
97
98
99 mpr = MPRester(API_KEY)
100 if mpr is None:
101 print(f"\nError: Can not get MPRester using the given API_KEY [{API_KEY}]\n")
102 input("Press ENTER to terminate>>\n")
103 exit()
104
105 if ',' in formula:
106 elements_in = formula.replace(' ', '').split(',')
107 search_results = mpr.materials.summary.search(elements = elements_in)
108 else:
109 elements_in = None
110 search_results = mpr.materials.search(formula = formula)
111 if not search_results:
112 print(f"No data found for {formula}")
113 return None
114
115 structures = []
116 for res in search_results:
117 material_id = res.material_id
118
119 material_data = mpr.materials.search(material_ids = [material_id])
120 if not material_data:
121 print(f"No structure data found for material_id {material_id}")
122 continue
123
124 structure_dict = material_data[0].structure.as_dict()
125 structure = Structure.from_dict(structure_dict)
126 composition = structure.composition
127 cformula = composition.reduced_formula
128# cformula = structure.reduced_formula #formula.replace(" ", "")
129# composition = Composition(cformula)
130 elements_res = [element.symbol for element in composition.elements]
131 if elements_in:
132# print("elements_res=", elements_res)
133# print("elements_in=", elements_in)
134 not_included = []
135 for e in elements_res:
136# print(" e=", e)
137 if e not in elements_in: not_included.append(e)
138
139 if len(not_included) >= 1:
140 print(f" ** One or more elements are not included for [{cformula}] in the given condition [{formula}]:", not_included)
141 continue
142 else:
143 print(f" ** Found [{cformula}] [{material_id}]")
144
145 structure.cmaterial = res
146 structure.material_id = material_id
147 structure.cformula = cformula
148 structure.celements = elements_res
149 structures.append(structure)
150 cformula = structure.formula.replace(" ", "")
151 print(f"Found material_id for {formula}: {material_id}: {cformula}")
152
153 return structures
154
155
156def save_structures(structures, output_format, formula):
157 """
158 概要: 取得した結晶構造を指定されたフォーマットでファイルに保存します。
159
160 詳細説明:
161 渡された結晶構造のリストを反復処理し、各構造を output_format に従ってファイルに書き出します。
162 SpacegroupAnalyzer を使用して構造を対称化してから保存します。
163 出力ファイル名は、構造の簡略化学式とMaterial IDに基づいて命名されます。
164 output_format が "poscar" の場合、最初のファイルは "POSCAR"、2番目以降は "POSCAR_2" などとなります。
165 その他のフォーマットの場合、"化学式_material_id.フォーマット" の形式で保存されます。
166
167 引数:
168 :param structures: 保存する結晶構造オブジェクトのリスト。
169 :type structures: list
170 :param output_format: 出力ファイルのフォーマット (例: "cif", "poscar")。
171 :type output_format: str
172 :param formula: 元の検索に使用された化学式 (ファイル名の一部として利用される可能性がありますが、実際はcformulaとmaterial_idが使われます)。
173 :type formula: str
174 """
175 print()
176 for i, structure in enumerate(structures):
177 cformula = structure.cformula
178 if output_format == "poscar":
179 if i == 0:
180 output_path = f"POSCAR"
181 else:
182 output_path = f"POSCAR_{i+1}"
183 else:
184 output_path = f"{cformula}_{structure.material_id}.{output_format}"
185 '''
186 if i == 0:
187 output_path = f"{cformula}.{output_format}"
188 else:
189 output_path = f"{cformula}_{i+1}.{output_format}"
190 '''
191
192 symmetry_analyzer = SpacegroupAnalyzer(structure, symprec = prec) #, angle_tolerance = 5.0)
193 symmetrized_structure = symmetry_analyzer.get_symmetrized_structure()
194# print()
195# print("symmetrized_structure:")
196# print(symmetrized_structure)
197
198 print(f"Saving {cformula} structure to [{output_path}]...")
199# structure.to(filename = output_path, fmt = output_format)
200 writer = CifWriter(symmetrized_structure, symprec = prec) #, angle_tolerance = 5.0)
201 writer.write_file(output_path)
202
203
204def main():
205 """
206 概要: スクリプトの主要な実行フローを制御します。
207
208 詳細説明:
209 update_vars を呼び出してコマンドライン引数を処理し、グローバル変数を設定します。
210 次に、get_structure を使用してMaterials Projectから結晶構造を取得します。
211 構造が正常に取得された場合、save_structures を呼び出してそれらの構造をファイルに保存します。
212 最後に、usage 関数を呼び出してスクリプトの使用方法を表示し、終了プロンプトを表示してユーザーの入力を待ちます。
213 """
214 update_vars()
215
216 structures = get_structure(formula)
217 if structures:
218 # output_formuat は typo なのでそのまま渡す
219 save_structures(structures, output_format, formula)
220
221 usage()
222 print()
223 input("Press ENTER to terminate>>\n")
224 exit()
225
226
227if __name__ == "__main__":
228 main()