# tkcif_reader files

## Files

- `tkcif_normalize.py`  
  CIF syntax-level normalizer. This is the `tkcif_base` layer.

- `tkcif_reader.py`  
  Public compatibility layer.

- `cif_inf_reader.py`  
  Console checker for one CIF file.

## Main API

```python
from tkcif_reader import read_structure, read_ase_atoms, read_tkcrystal

structure = read_structure("sample.cif")
structure, info = read_structure("sample.cif", return_info=True)

atoms = read_ase_atoms("sample.cif")
atoms, info = read_ase_atoms("sample.cif", return_info=True)

cry = read_tkcrystal("sample.cif")
cry, info = read_tkcrystal("sample.cif", return_info=True)
```

## Backend order of `read_structure()`

1. `pymatgen`
2. `tkcif_base+pymatgen`
3. `ase+pymatgen`
4. `tkcif_legacy+pymatgen`

`read_structure()` always returns a pymatgen `Structure` object unless it fails.

If pymatgen itself is unavailable or unusable, use:

```python
cry = read_tkcrystal("sample.cif")
```

This returns the legacy `tkCrystal` object.

## Console check

```bash
python cif_inf_reader.py sample.cif
```

ASE diagnostic path:

```bash
python cif_inf_reader.py sample.cif --reader ase
```

Emergency legacy path:

```bash
python cif_inf_reader.py sample.cif --reader tkcrystal
```

## Notes for legacy tkCIF

`read_tkcrystal()` tries these import paths:

1. `tklib.tkcrystal.tkcif`
2. `tkcrystal.tkcif`
3. `tkcif`

If your actual legacy module path is different, call:

```python
cry, info = read_tkcrystal(
    "sample.cif",
    return_info=True,
    module_candidates=["your.module.path"],
)
```

The adapter `tkcrystal_to_pymatgen_structure()` is intentionally isolated.
Adjust that function if your exact `tkCrystal` or atom-site API differs.


## ASE backend

`read_ase_atoms()` reads the CIF through `ase.io.read()` and returns an ASE `Atoms` object.

`read_structure()` can use the `ase+pymatgen` backend:

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

The conversion function is isolated here:

```python
ase_atoms_to_pymatgen_structure(atoms)
```

It first tries `pymatgen.io.ase.AseAtomsAdaptor.get_structure(atoms)`.
If that fails, it falls back to a direct conversion using cell, chemical symbols,
and scaled positions.
