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