Build a :class:`Structure` object from a dictionary with ABINIT variables.

    Args:
        cls: Structure class to be instantiated. pymatgen.core.structure.Structure if cls is None

    example:

        al_structure = structure_from_abivars(
            acell=3*[7.5],
            rprim=[0.0, 0.5, 0.5,
                   0.5, 0.0, 0.5,
                   0.5, 0.5, 0.0],
            typat=1,
            xred=[0.0, 0.0, 0.0],
            ntypat=1,
            znucl=13,
        )

    `xred` can be replaced with `xcart` or `xangst`.

def structure_from_abivars(cls=None, *args, **kwargs):
    """
    Build a :class:`Structure` object from a dictionary with ABINIT variables.

    Args:
        cls: Structure class to be instantiated. pymatgen.core.structure.Structure if cls is None

    example:

        al_structure = structure_from_abivars(
            acell=3*[7.5],
            rprim=[0.0, 0.5, 0.5,
                   0.5, 0.0, 0.5,
                   0.5, 0.5, 0.0],
            typat=1,
            xred=[0.0, 0.0, 0.0],
            ntypat=1,
            znucl=13,
        )

    `xred` can be replaced with `xcart` or `xangst`.
    """
    kwargs.update(dict(*args))
    d = kwargs

    cls = Structure if cls is None else cls

    #lattice = Lattice.from_dict(d, fmt="abivars")
    lattice = lattice_from_abivars(**d)
    coords, coords_are_cartesian = d.get("xred", None), False

    if coords is None:
        coords = d.get("xcart", None)
        if coords is not None:
            if "xangst" in d:
                raise ValueError("xangst and xcart are mutually exclusive")
            coords = ArrayWithUnit(coords, "bohr").to("ang")
        else:
            coords = d.get("xangst", None)
        coords_are_cartesian = True

    if coords is None:
        raise ValueError("Cannot extract coordinates from:\n %s" % str(d))

    coords = np.reshape(coords, (-1,3))

    znucl_type, typat = d["znucl"], d["typat"]

    if not isinstance(znucl_type, collections.abc.Iterable):
        znucl_type = [znucl_type]

    if not isinstance(typat, collections.abc.Iterable):
        typat = [typat]

    if len(typat) != len(coords):
        raise ValueError("len(typat) != len(coords):\ntypat: %s\ncoords: %s" % (typat, coords))

    # Note conversion to int and Fortran --> C indexing
    typat = np.array(typat, dtype=np.int)
    species = [znucl_type[typ-1] for typ in typat]

    return cls(lattice, species, coords, validate_proximity=False,
               to_unit_cell=False, coords_are_cartesian=coords_are_cartesian)