File size: 3,910 Bytes
3825ff2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | # -*- coding: utf-8 -*-
"""μ μ λ¨κ³ κ²μ¬.
μ¬κΈ°μ 보λ κ²μ **νμκ³Ό μ격**λΏμ΄λ€. μ€μ μ±μ (μ κΈ°ννμ°½Β·λ¦¬ν¬ μ΄λ)μ μμ»€κ° νλ€.
μ€νμ΄μ€λ MP λ°μ΄ν°λ GPU λ μμΌλ―λ‘, μ¬κΈ°μ λ¬Όμ±μ νμ νλ μ²νλ©΄ μ λλ€.
κ±°μ μ μ°Έκ°μκ° **κ³ μΉ μ μλ κ²**μλ§ μ΄λ€. κ°μ μ»μ§ λͺ»ν νλͺ©μ κ±°μ μ΄ μλλΌ λ³΄λ₯λ‘ λλ€.
"""
import re
# μ±μ λμ μμ.
SUPPORTED = set("""
H Li Be B C N O F Na Mg Al Si P S Cl K Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn
Ga Ge As Se Br Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Cs Ba
La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu Hf Ta W Re Os Ir Pt Au Hg
Tl Pb Bi Ac Th Pa U Np Pu
""".split())
_CIF_HINT = ("data_", "_cell_length_a", "_atom_site")
def parse_formula(text):
"""ννμμ μ‘°μ±μΌλ‘. **κ΄νΈλ₯Ό λ°λμ μ²λ¦¬νλ€.**
μ§μ μ κ·μμΌλ‘ νμΌλ©΄ `LiZr2(PO4)3` κ° P1O4 κ° λμ΄ μ‘°μ±μ΄ ν΅μ§Έλ‘ νλ¦°λ€.
Materials Project μμ μ΄ LGPS λ₯Ό `Li10Ge(PS6)2` λ‘ μ μΌλ―λ‘ μ΄κ±΄ μμΈκ° μλλΌ κΈ°λ³Έμ΄λ€.
"""
from pymatgen.core import Composition
c = Composition(str(text).strip())
return {str(k): float(v) for k, v in c.get_el_amt_dict().items()}
def check(text, cif=None, require_elements=("Li",), max_atoms=60,
supported=None, max_elements=6):
"""μ μ νμ . (ok, reason, info) λ₯Ό λλ €μ€λ€."""
supported = supported or SUPPORTED
raw = (text or "").strip()
if not raw:
return False, "ννμμ μ
λ ₯ν΄ μ£ΌμΈμ.", {}
if len(raw) > 120:
return False, "ννμμ΄ λ무 κΉλλ€.", {}
if not re.match(r"^[A-Za-z0-9()\[\]\.\s]+$", raw):
return False, "ννμμ μΈ μ μλ λ¬Έμκ° μμ΅λλ€.", {}
try:
comp = parse_formula(raw)
except Exception:
return False, "ννμμ ν΄μνμ§ λͺ»νμ΅λλ€. μ: Li3YCl6, LiZr2(PO4)3", {}
if not comp:
return False, "ννμμ ν΄μνμ§ λͺ»νμ΅λλ€.", {}
for el in require_elements:
if el not in comp:
return False, "λ¦¬ν¬ μ ν΄μ§ μμ¦μ
λλ€. %s λ₯Ό ν¬ν¨ν΄μΌ ν©λλ€." % el, {}
bad = sorted(e for e in comp if e not in supported)
if bad:
return False, ("κ³μ° κΈ°μ€ μνκ° μλ μμμ
λλ€: %s" % ", ".join(bad)), {}
if len(comp) > max_elements:
return False, "μμκ° %d μ’
μ λμ΅λλ€ (νμ¬ %d μ’
)." % (max_elements, len(comp)), {}
# **κΈ°μ½ μ‘°μ±**μ κΈ°μ€μΌλ‘ μΌλλ€. Li3YCl6 μ Li9Y3Cl18 μ κ°μ λ¬Όμ§μ΄λ―λ‘ κ°μ κ²μΌλ‘
# μΈμΌ νλ€. μλ³Έ μ‘°μ±μΌλ‘ μ΄μ λ₯Ό λ§λ€λ©΄ λ°°μλ§ λ°κΏ κ°μ λ¬Όμ§μ λͺ λ²μ΄κ³ μ¬λ¦΄ μ μλ€.
from math import gcd
from functools import reduce
integral = all(abs(v - round(v)) < 1e-6 for v in comp.values())
if integral:
ints = {k: int(round(v)) for k, v in comp.items()}
g = reduce(gcd, ints.values()) or 1
reduced = {k: v // g for k, v in ints.items()}
else:
reduced = dict(comp) # λΉμ μ μ‘°μ±(λν λ±)μ κ·Έλλ‘ λλ€
n_atom = sum(reduced.values())
if n_atom > max_atoms:
return False, ("κΈ°μ½ μ‘°μ±μ μμ μκ° %d κ°λ‘ μν %d λ₯Ό λμ΅λλ€."
% (n_atom, max_atoms)), {}
info = {"composition": comp, "reduced": reduced,
"n_atoms": n_atom, "n_elements": len(comp)}
if cif:
c = str(cif)
if len(c) > 400_000:
return False, "ꡬ쑰 νμΌμ΄ λ무 ν½λλ€ (400KB μν).", {}
if not any(h in c for h in _CIF_HINT):
return False, "ꡬ쑰 νμΌμ΄ CIF νμμΌλ‘ 보μ΄μ§ μμ΅λλ€.", {}
info["has_structure"] = True
return True, "", info
|