Skip to content

defectpl.defect_utils

make_defect_entry

make_defect_entry(
    name,
    center=None,
    perfect_poscar=None,
    defect_poscar=None,
    out_path="defect_entry.json",
    site_tol=0.5,
)

Create a defect_entry.json file.

Either supply center directly, or let the function auto-detect it by comparing perfect_poscar and defect_poscar.

Parameters:

Name Type Description Default
name str

Defect label (e.g. "Va_O1_2" for an oxygen vacancy with charge +2).

required
center sequence of 3 floats

Fractional coordinates of the defect centre. Required when perfect_poscar / defect_poscar are not provided.

None
perfect_poscar str or Path

Path to the perfect (undoped) supercell POSCAR/CONTCAR.

None
defect_poscar str or Path

Path to the defect supercell POSCAR/CONTCAR.

None
out_path str or Path

Destination for the JSON file. Default "defect_entry.json".

'defect_entry.json'
site_tol float

Cartesian tolerance (Å) for matching sites in auto-detection.

0.5

Returns:

Type Description
dict

The JSON content that was written.

Raises:

Type Description
ValueError

If neither center nor both structure files are provided.

Source code in defectpl\defect_utils.py
def make_defect_entry(
    name: str,
    center: Optional[Sequence[float]] = None,
    perfect_poscar: Optional[str | Path] = None,
    defect_poscar: Optional[str | Path] = None,
    out_path: str | Path = "defect_entry.json",
    site_tol: float = 0.5,
) -> dict:
    """
    Create a ``defect_entry.json`` file.

    Either supply ``center`` directly, or let the function auto-detect it by
    comparing ``perfect_poscar`` and ``defect_poscar``.

    Parameters
    ----------
    name : str
        Defect label (e.g. ``"Va_O1_2"`` for an oxygen vacancy with charge +2).
    center : sequence of 3 floats, optional
        Fractional coordinates of the defect centre.  Required when
        ``perfect_poscar`` / ``defect_poscar`` are not provided.
    perfect_poscar : str or Path, optional
        Path to the perfect (undoped) supercell POSCAR/CONTCAR.
    defect_poscar : str or Path, optional
        Path to the defect supercell POSCAR/CONTCAR.
    out_path : str or Path, optional
        Destination for the JSON file.  Default ``"defect_entry.json"``.
    site_tol : float, optional
        Cartesian tolerance (Å) for matching sites in auto-detection.

    Returns
    -------
    dict
        The JSON content that was written.

    Raises
    ------
    ValueError
        If neither ``center`` nor both structure files are provided.
    """
    if center is not None:
        defect_center = list(float(x) for x in center)
        defect_type = "manual"
    elif perfect_poscar is not None and defect_poscar is not None:
        defect_center, defect_type = detect_defect_center(
            perfect_poscar, defect_poscar, site_tol=site_tol
        )
        logger.info(
            "Auto-detected defect type '%s', centre: %s", defect_type, defect_center
        )
    else:
        raise ValueError(
            "Provide either --center or both --perfect and --defect structure files."
        )

    payload = {
        "schema_version": DEFECT_ENTRY_SCHEMA_VERSION,
        "name": name,
        "defect_center": defect_center,
        "defect_type": defect_type,
    }

    out_path = Path(out_path)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with open(out_path, "w") as fh:
        json.dump(payload, fh, indent=2)

    logger.info("defect_entry.json written: %s", out_path)
    return payload

make_defect_structure_info

make_defect_structure_info(
    poscar,
    defect_center_frac,
    cutoff_radius=3.5,
    out_path="defect_structure_info.json",
)

Generate a defect_structure_info.json via distance-based neighbour search.

Finds all atoms within cutoff_radius Å of defect_center_frac in the supercell defined by poscar (minimum-image convention).

Parameters:

Name Type Description Default
poscar str or Path

POSCAR / CONTCAR of the defect supercell.

required
defect_center_frac sequence of 3 floats

Fractional coordinates of the defect centre.

required
cutoff_radius float

Search radius in Å. Default 3.5 Å.

3.5
out_path str or Path

Destination file. Default "defect_structure_info.json".

'defect_structure_info.json'

Returns:

Type Description
dict

The JSON content that was written, with key "neighbor_atom_indices".

Raises:

Type Description
ImportError

If pymatgen is not installed.

Source code in defectpl\defect_utils.py
def make_defect_structure_info(
    poscar: str | Path,
    defect_center_frac: Sequence[float],
    cutoff_radius: float = 3.5,
    out_path: str | Path = "defect_structure_info.json",
) -> dict:
    """
    Generate a ``defect_structure_info.json`` via distance-based neighbour search.

    Finds all atoms within *cutoff_radius* Å of *defect_center_frac* in the
    supercell defined by *poscar* (minimum-image convention).

    Parameters
    ----------
    poscar : str or Path
        POSCAR / CONTCAR of the defect supercell.
    defect_center_frac : sequence of 3 floats
        Fractional coordinates of the defect centre.
    cutoff_radius : float, optional
        Search radius in Å.  Default 3.5 Å.
    out_path : str or Path, optional
        Destination file.  Default ``"defect_structure_info.json"``.

    Returns
    -------
    dict
        The JSON content that was written, with key ``"neighbor_atom_indices"``.

    Raises
    ------
    ImportError
        If pymatgen is not installed.
    """
    from pymatgen.core import Structure

    poscar = Path(poscar)
    struct = Structure.from_file(str(poscar))
    center = np.array(defect_center_frac, dtype=float)

    neighbors: List[dict] = []
    for i, site in enumerate(struct):
        diff = center - site.frac_coords
        diff -= np.round(diff)  # minimum image
        d = float(np.linalg.norm(struct.lattice.get_cartesian_coords(diff)))
        if d < cutoff_radius:
            neighbors.append(
                {"index": i, "element": str(site.specie), "distance": round(d, 5)}
            )

    indices = [n["index"] for n in neighbors]

    payload = {
        "poscar": str(poscar),
        "defect_center_frac": list(float(x) for x in defect_center_frac),
        "cutoff_radius": cutoff_radius,
        "n_neighbors": len(indices),
        "neighbor_atom_indices": indices,
        "neighbors": neighbors,
    }

    out_path = Path(out_path)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with open(out_path, "w") as fh:
        json.dump(payload, fh, indent=2)

    logger.info(
        "defect_structure_info.json written: %s  (%d neighbours)",
        out_path,
        len(indices),
    )
    return payload