# tkcif 生成AI投入用コンテキスト

> このファイルは `tkcif` を使うコード生成のため、マニュアルとAPIリファレンスを1ファイルへ統合したものです。API名・引数は下記APIリファレンスを優先し、存在しないAPIを推測で作らないでください。ソースコードが同時に与えられた場合はソースコードを最優先します。

---

# tkcif マニュアル

## 1. 役割

`tkcif` は、CIFを単一のreaderに固定せず、複数backendを順番に試して**可能な限り `pymatgen.Structure` を得る**ための互換・正規化レイヤーです。壊れ気味のCIFに対しては、構文正規化、ASE経由、旧 `tkCIF` 経由をfallbackとして使います。

## 2. 推奨import

現在の `tkcif/__init__.py` は公開関数を再exportしていません。次のモジュールimportを使ってください。

```python
from tkcif.tkcif_reader import (
    CIFReadError,
    CIFReadInfo,
    read_structure,
    read_ase_atoms,
    read_tkcrystal,
    normalize_cif,
)
```

`from tkcif import read_structure` は現状のソースでは使えません。

## 3. 最小例

```python
from tkcif.tkcif_reader import read_structure

structure, info = read_structure("sample.cif", return_info=True)
print(structure.formula)
print(info.backend)
print(info.short_report())
```

通常は `primitive=False` のままにして、CIFに書かれたセルを保持します。

## 4. `read_structure()` のfallback順序

既定順序は次です。

1. `pymatgen`: pymatgenで直接読む
2. `tkcif_base+pymatgen`: `tkcif_normalize.py` で正規化してからpymatgenで読む
3. `ase+pymatgen`: ASEで読み、`pymatgen.Structure`へ変換
4. `tkcif_legacy+pymatgen`: 旧 `tkCIF` → `tkCrystal` → `pymatgen.Structure`

特定backendだけを試す場合:

```python
structure, info = read_structure(
    "sample.cif",
    return_info=True,
    backend_order=["tkcif_base+pymatgen", "ase+pymatgen"],
)
```

すべて失敗すると `CIFReadError` が発生し、試行backendと各エラーがメッセージに含まれます。

## 5. 診断情報 `CIFReadInfo`

主要フィールド:

| フィールド | 内容 |
|---|---|
| `path` | 入力CIFパス |
| `backend` | 成功したbackend |
| `attempted_backends` | 試行したbackend一覧 |
| `unavailable_backends` | 未導入・利用不能backend |
| `errors` | 読み込み失敗の要約 |
| `warnings` | parser警告 |
| `normalized` | 正規化を経由したか |
| `encoding` | 推定された文字コード |
| `fallback_object` | ASE Atomsまたは旧tkCrystalの参照 |

`return_info=True` は、研究データの再現性確保や大量処理時のログ保存に推奨です。

## 6. ASEまたは旧tkCrystalを直接得る

```python
from tkcif.tkcif_reader import read_ase_atoms, read_tkcrystal

atoms = read_ase_atoms("sample.cif")
legacy_crystal = read_tkcrystal("sample.cif")
```

これらはpymatgenに依存しない診断経路です。`read_tkcrystal()` のlegacy module候補は `module_candidates=` で上書きできます。

## 7. CIF正規化

```python
from tkcif.tkcif_reader import normalize_cif

normalized_text, document, warnings, encoding = normalize_cif("broken.cif")
```

ファイルとして正規化する低レベルAPIは `tkcif.tkcif_normalize.normalize_cif_file()` です。正規化層は、空白・改行・引用・loop・複数行text fieldなどをlenientに処理しますが、**結晶学的妥当性を保証するものではありません**。

## 8. 構造変換ヘルパー

- `ase_atoms_to_pymatgen_structure(atoms)`
- `tkcrystal_to_pymatgen_structure(cry)`

旧 `tkCrystal` の具体的な属性構造が環境ごとに異なる場合、後者のadapter調整が必要です。

## 9. サマリー生成

```python
from tkcif.tkcif_reader import structure_summary_text

print(structure_summary_text(structure, symprec=1.0e-3))
```

ASEと旧tkCrystalにも、それぞれbest-effortのサマリー関数があります。

## 10. CLI

```bash
python -m tkcif.cif_inf_reader sample.cif
python -m tkcif.cif_inf_reader sample.cif --reader ase
python -m tkcif.cif_inf_reader sample.cif --reader tkcrystal
```

## 11. 依存関係

- 主backend: `pymatgen`
- optional fallback: `ase`
- legacy fallback: 旧 `tkCIF` / `tkCrystal` 実装
- 正規化コア: 標準ライブラリ中心

## 12. 生成AI向けコード生成ルール

1. 既定の戻り値は `pymatgen.Structure` とし、辞書やASE Atomsと誤認しない。
2. 読み込み経路を記録する必要があるコードでは必ず `return_info=True` を使う。
3. `tkcif` トップレベルから関数をimportせず、`tkcif.tkcif_reader` を使う。
4. CIF読込失敗を単純な `FileNotFoundError` だけと仮定せず、`CIFReadError` を扱う。
5. 正規化は構文補正であり、占有率、空間群、組成、密度の物理的妥当性検証とは分ける。
6. 旧tkCrystal adapterの属性名を推測で決めない。対象実装を確認してから変更する。


---

# tkcif APIリファレンス

> 対象ソース: `tklib2.zip`（解析日: 2026-08-03）。この文書はソースコードを静的解析して生成しています。

## APIの読み方

- **パッケージ公開API**は、原則としてトップレベルの `__all__` に含まれる名前です。
- **モジュールAPI**には、公開名（先頭が `_` でない関数・クラス・メソッド）を列挙しています。
- docstringがないAPIでは、シグネチャとソースパスを一次情報として扱ってください。
- 生成AIは、この文書に存在しない引数・戻り値・メソッドを推測で追加しないでください。

## パッケージ公開API

`tkcif/__init__.py` に `__all__` は定義されていません。推奨import経路はマニュアルを参照してください。

## モジュール一覧

| モジュール | ソース | 関数 | クラス |
|---|---|---:|---:|
| `tkcif` | `tkcif/__init__.py` | 0 | 0 |
| `tkcif.cif_inf_reader` | `tkcif/cif_inf_reader.py` | 1 | 0 |
| `tkcif.tkcif_normalize` | `tkcif/tkcif_normalize.py` | 25 | 6 |
| `tkcif.tkcif_reader` | `tkcif/tkcif_reader.py` | 10 | 2 |

## `tkcif`

ソース: `tkcif/__init__.py`

_このモジュールには静的解析で検出された公開関数・クラス・定数はありません。_

## `tkcif.cif_inf_reader`

ソース: `tkcif/cif_inf_reader.py`

cif_inf_reader.py

Console checker for tkcif_reader.py.

Usage:
    python cif_inf_reader.py sample.cif

Default:
    use read_structure(), i.e. pymatgen Structure with fallback order:
      pymatgen -> tkcif_base+pymatgen -> tkcif_legacy+pymatgen

Emergency tkCrystal path:
    python cif_inf_reader.py sample.cif --reader tkcrystal

### function `main`

```python
def main() -> int
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

## `tkcif.tkcif_normalize`

ソース: `tkcif/tkcif_normalize.py`

tkcif_normalize.py

A small, dependency-free CIF normalizer/tester intended as the first step of
"tkcif_base".  It is deliberately a syntax-level normalizer, not a crystal
structure interpreter.

Default behavior under __main__:
    - recursively search *.cif below the current directory
    - read each CIF
    - parse and normalize it in memory
    - re-parse the normalized text as a self-check
    - print failed paths only, plus a summary
    - do not write any output files

The parser is lenient for common broken CIFs:
    - key without inline value followed by unquoted continuation lines
    - semicolon text fields
    - quoted values
    - loops with quoted values
    - missing initial data_ header, which is repaired in memory

Author: tkCIF cleanup helper

### class `CIFNormalizeError` — bases: `Exception`

Raised when CIF normalization fails.

### class `CIFValue`

_ソース内docstringはありません。シグネチャと実装を参照してください。_

**データクラス相当の初期化フィールド**

```python
CIFValue(raw: str, value: str, compact: str, source: str = 'normal', multiline: bool = False, warnings: list[str])
```

**フィールド**

| 名前 | 型 | 既定値 |
|---|---|---|
| `raw` | `str` | `必須` |
| `value` | `str` | `必須` |
| `compact` | `str` | `必須` |
| `source` | `str` | `'normal'` |
| `multiline` | `bool` | `False` |
| `warnings` | `list[str]` | `必須` |

### class `CIFLoop`

_ソース内docstringはありません。シグネチャと実装を参照してください。_

**データクラス相当の初期化フィールド**

```python
CIFLoop(keys: list[str], rows: list[list[CIFValue]], warnings: list[str])
```

**フィールド**

| 名前 | 型 | 既定値 |
|---|---|---|
| `keys` | `list[str]` | `必須` |
| `rows` | `list[list[CIFValue]]` | `必須` |
| `warnings` | `list[str]` | `必須` |

### class `CIFItem`

_ソース内docstringはありません。シグネチャと実装を参照してください。_

**データクラス相当の初期化フィールド**

```python
CIFItem(kind: ItemKind, key: str | None = None, value: CIFValue | None = None, loop: CIFLoop | None = None, text: str | None = None)
```

**フィールド**

| 名前 | 型 | 既定値 |
|---|---|---|
| `kind` | `ItemKind` | `必須` |
| `key` | `str | None` | `None` |
| `value` | `CIFValue | None` | `None` |
| `loop` | `CIFLoop | None` | `None` |
| `text` | `str | None` | `None` |

### class `CIFBlock`

_ソース内docstringはありません。シグネチャと実装を参照してください。_

**データクラス相当の初期化フィールド**

```python
CIFBlock(name: str, items: list[CIFItem], warnings: list[str])
```

**フィールド**

| 名前 | 型 | 既定値 |
|---|---|---|
| `name` | `str` | `必須` |
| `items` | `list[CIFItem]` | `必須` |
| `warnings` | `list[str]` | `必須` |

### class `CIFDocument`

_ソース内docstringはありません。シグネチャと実装を参照してください。_

**データクラス相当の初期化フィールド**

```python
CIFDocument(blocks: list[CIFBlock], warnings: list[str])
```

**フィールド**

| 名前 | 型 | 既定値 |
|---|---|---|
| `blocks` | `list[CIFBlock]` | `必須` |
| `warnings` | `list[str]` | `必須` |

**メソッド／プロパティ**

#### method `CIFDocument.to_canonical_text`

```python
def to_canonical_text(self, *, compact_multiline: bool = True) -> str
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `normalize_whitespace`

```python
def normalize_whitespace(value: str) -> str
```

Compact any whitespace sequence to a single space.

### function `safe_data_name`

```python
def safe_data_name(name: str) -> str
```

Make a simple data_ block name.

### function `is_reserved_word`

```python
def is_reserved_word(token: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `quote_cif_value`

```python
def quote_cif_value(value: str | None) -> str
```

Quote a value so that the result can be written as CIF-like text.

This is conservative.  It does not attempt semantic repairs; it only makes
scalar tokens safe for later parsers such as pymatgen.

### function `read_text_guess`

```python
def read_text_guess(path: Path) -> tuple[str, str]
```

Read a text file with a few practical encodings.

### function `normalize_newlines`

```python
def normalize_newlines(text: str) -> str
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `split_key_value_line`

```python
def split_key_value_line(line: str) -> tuple[str, str]
```

Split a CIF scalar line into key and rest.

Example:
    _cell_length_a  4.0  -> ('_cell_length_a', '4.0')
    _key                 -> ('_key', '')

### function `line_starts_text_field`

```python
def line_starts_text_field(line: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `is_comment_line`

```python
def is_comment_line(line: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `is_blank_line`

```python
def is_blank_line(line: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `is_data_line`

```python
def is_data_line(line: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `is_loop_line`

```python
def is_loop_line(line: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `is_key_line`

```python
def is_key_line(line: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `is_new_item_line`

```python
def is_new_item_line(line: str) -> bool
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `strip_inline_comment_unquoted`

```python
def strip_inline_comment_unquoted(rest: str) -> str
```

Strip an inline comment from an unquoted scalar value.

We only treat ' #' or leading '#' as comment start.  This avoids damaging
tokens that contain # without whitespace.

### function `parse_quoted_or_token_line`

```python
def parse_quoted_or_token_line(line: str) -> tuple[list[CIFValue], list[str]]
```

Tokenize one CIF data line for loop rows.

This is intentionally lenient.  It understands single/double quoted values
and treats '#' outside quotes as comment start.  It does not implement the
full CIF grammar; semicolon text fields are handled outside this function.

### function `parse_scalar_inline_value`

```python
def parse_scalar_inline_value(rest: str) -> CIFValue
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `read_text_field`

```python
def read_text_field(lines: list[str], i: int) -> tuple[CIFValue, int, list[str]]
```

Read a semicolon-delimited CIF text field starting at line i.

### function `read_inferred_continuation`

```python
def read_inferred_continuation(lines: list[str], i: int) -> tuple[CIFValue, int, list[str]]
```

Read non-standard unquoted continuation lines until the next CIF item.

This reproduces the useful tkCIF behavior: if a key has no inline value and
the next line is not clearly another key, read lines as the value until the
next key/loop/data line.

### function `parse_loop`

```python
def parse_loop(lines: list[str], i: int) -> tuple[CIFItem, int, list[str]]
```

Parse loop_ beginning at line i.

### function `parse_cif_text`

```python
def parse_cif_text(text: str, *, source: str = '<string>') -> CIFDocument
```

Parse CIF text into a lenient normalized document model.

### function `collect_warnings`

```python
def collect_warnings(doc: CIFDocument) -> list[str]
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `normalize_cif_file`

```python
def normalize_cif_file(path: Path, *, self_check: bool = True) -> tuple[str, CIFDocument, list[str], str]
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `iter_cif_paths`

```python
def iter_cif_paths(root: Path, patterns: Iterable[str]) -> list[Path]
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `main`

```python
def main() -> int
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

## `tkcif.tkcif_reader`

ソース: `tkcif/tkcif_reader.py`

tkcif_reader.py

Thin compatibility layer for CIF reading.

Public API
----------
read_structure(path)
    Return a pymatgen Structure object.

read_structure(path, return_info=True)
    Return (Structure, CIFReadInfo).

read_ase_atoms(path)
    Return an ASE Atoms object using ase.io.read.

read_ase_atoms(path, return_info=True)
    Return (ase.Atoms, CIFReadInfo).

read_tkcrystal(path)
    Return a legacy tkCrystal object using tkCIF.

read_tkcrystal(path, return_info=True)
    Return (tkCrystal, CIFReadInfo).

Backend order for read_structure()
----------------------------------
1. pymatgen direct CIF reading
2. tkcif_base normalization by tkcif_normalize.py, then pymatgen
3. ASE -> pymatgen Structure
4. legacy tkCIF -> tkCrystal -> pymatgen Structure

Notes
-----
- This module intentionally catches ImportError/Exception for optional backends.
- Legacy tkCIF support is a best-effort scaffold. You may need to adjust
  tkcrystal_to_pymatgen_structure() for your exact tkCrystal API.

### class `CIFReadError` — bases: `RuntimeError`

Raised when all CIF reading backends fail.

### class `CIFReadInfo`

_ソース内docstringはありません。シグネチャと実装を参照してください。_

**データクラス相当の初期化フィールド**

```python
CIFReadInfo(path: str, backend: str = '', attempted_backends: list[str], unavailable_backends: list[str], errors: list[str], warnings: list[str], normalized: bool = False, encoding: str | None = None, fallback_object: Any | None = None)
```

**フィールド**

| 名前 | 型 | 既定値 |
|---|---|---|
| `path` | `str` | `必須` |
| `backend` | `str` | `''` |
| `attempted_backends` | `list[str]` | `必須` |
| `unavailable_backends` | `list[str]` | `必須` |
| `errors` | `list[str]` | `必須` |
| `warnings` | `list[str]` | `必須` |
| `normalized` | `bool` | `False` |
| `encoding` | `str | None` | `None` |
| `fallback_object` | `Any | None` | `None` |

**メソッド／プロパティ**

#### method `CIFReadInfo.add_error`

```python
def add_error(self, backend: str, exc: BaseException) -> None
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

#### method `CIFReadInfo.add_unavailable`

```python
def add_unavailable(self, backend: str, reason: str) -> None
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

#### method `CIFReadInfo.short_report`

```python
def short_report(self) -> str
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `read_structure`

```python
def read_structure(path: str | Path, *, primitive: bool = False, return_info: bool = False, backend_order: Iterable[str] | None = None) -> Any
```

Read one CIF file and return a pymatgen Structure object.

Parameters
----------
path:
    CIF path.
primitive:
    Passed to pymatgen parser. False preserves the CIF cell.
return_info:
    If True, return (structure, CIFReadInfo).
    If False, return structure only.
backend_order:
    Optional backend names.
    Available names:
        "pymatgen"
        "tkcif_base+pymatgen"
        "ase+pymatgen"
        "tkcif_legacy+pymatgen"

### function `read_ase_atoms`

```python
def read_ase_atoms(path: str | Path, *, return_info: bool = False, index: int | str | None = None, format: str | None = None) -> Any
```

Read one CIF file using ASE and return an ase.Atoms object.

This function is independent of pymatgen.  It can be used as a diagnostic
or as a fallback source for read_structure() through ase+pymatgen.

Parameters
----------
path:
    CIF path.
return_info:
    If True, return (ase.Atoms, CIFReadInfo).
index:
    Passed to ase.io.read.  Default None usually means the first readable
    configuration.  Use ":" if you want to experiment with all structures
    outside this wrapper.
format:
    Optional ASE format.  If omitted, ASE guesses from the file name.

### function `read_tkcrystal`

```python
def read_tkcrystal(path: str | Path, *, return_info: bool = False, module_candidates: Iterable[str] | None = None) -> Any
```

Read one CIF file using legacy tkCIF and return a tkCrystal object.

This function is independent of pymatgen. It is the emergency path when
pymatgen cannot be used at all.

### function `normalize_cif`

```python
def normalize_cif(path: str | Path) -> tuple[str, Any, list[str], str]
```

Normalize one CIF by tkcif_normalize.py.

Returns
-------
normalized_text, document, warnings, encoding

### function `ase_atoms_to_pymatgen_structure`

```python
def ase_atoms_to_pymatgen_structure(atoms: Any) -> Any
```

Convert ASE Atoms to pymatgen Structure.

Preferred path:
    pymatgen.io.ase.AseAtomsAdaptor.get_structure(atoms)

Fallback path:
    manually construct Structure from atoms.cell, atoms.get_chemical_symbols(),
    atoms.get_scaled_positions(), and periodic boundary flags.

Notes
-----
- CIF occupancy/disorder information may already be simplified by ASE.
- If the ASE Atoms object is not 3D periodic, this function still tries to
  create a Structure, but appends a warning only at the read_ase_atoms()
  stage.  For molecules or clusters, pymatgen Molecule may be more suitable.

### function `tkcrystal_to_pymatgen_structure`

```python
def tkcrystal_to_pymatgen_structure(cry: Any) -> Any
```

Convert legacy tkCrystal to pymatgen Structure.

This is intentionally written as an adapter function so that you can adjust
it to the exact tkCrystal API without touching read_structure().

Expected tkCrystal-like methods:
    cry.LatticeParameters()
    cry.AtomSiteList()

Expected atom-site-like methods:
    site.AtomNameOnly()
    site.Position()
    site.Occupancy()

### function `structure_summary_text`

```python
def structure_summary_text(structure: Any, *, symprec: float = 0.001) -> str
```

Return a human-readable summary for a pymatgen Structure.

### function `species_string`

```python
def species_string(site: Any) -> str
```

_ソース内docstringはありません。シグネチャと実装を参照してください。_

### function `ase_atoms_summary_text`

```python
def ase_atoms_summary_text(atoms: Any) -> str
```

Best-effort summary for ASE Atoms.

### function `tkcrystal_summary_text`

```python
def tkcrystal_summary_text(cry: Any) -> str
```

Best-effort summary for legacy tkCrystal.

