Generate a structure using a magnetic spacegroup. Note that only
        symmetrically distinct species, coords and magmoms should be provided.]
        All equivalent sites are generated from the spacegroup operations.

        Args:
            msg (str/list/:class:`pymatgen.symmetry.maggroups.MagneticSpaceGroup`):
                The magnetic spacegroup.
                If a string, it will be interpreted as one of the notations
                supported by MagneticSymmetryGroup, e.g., "R-3'c" or "Fm'-3'm".
                If a list of two ints, it will be interpreted as the number of
                the spacegroup in its Belov, Neronova and Smirnova (BNS) setting.
            lattice (Lattice/3x3 array): The lattice, either as a
                :class:`pymatgen.core.lattice.Lattice` or
                simply as any 2D array. Each row should correspond to a lattice
                vector. E.g., [[10,0,0], [20,10,0], [0,0,30]] specifies a
                lattice with lattice vectors [10,0,0], [20,10,0] and [0,0,30].
                Note that no attempt is made to check that the lattice is
                compatible with the spacegroup specified. This may be
                introduced in a future version.
            species ([Specie]): Sequence of species on each site. Can take in
                flexible input, including:
                i.  A sequence of element / specie specified either as string
                symbols, e.g. ["Li", "Fe2+", "P", ...] or atomic numbers,
                e.g., (3, 56, ...) or actual Element or Specie objects.

                ii. List of dict of elements/species and occupancies, e.g.,
                    [{"Fe" : 0.5, "Mn":0.5}, ...]. This allows the setup of
                    disordered structures.
            coords (Nx3 array): list of fractional/cartesian coordinates of
                each species.
            site_properties (dict): Properties associated with the sites as a
                dict of sequences, e.g., {"magmom":[5,5,5,5]}. The sequences
                have to be the same length as the atomic species and
                fractional_coords. Unlike Structure.from_spacegroup(),
                this argument is mandatory, since magnetic moment information
                has to be included. Note that the *direction* of the supplied
                magnetic moment relative to the crystal is important, even if
                the resulting structure is used for collinear calculations.
            coords_are_cartesian (bool): Set to True if you are providing
                coordinates in cartesian coordinates. Defaults to False.
            tol (float): A fractional tolerance to deal with numerical
                precision issues in determining if orbits are the same.

def from_magnetic_spacegroup(
            cls, msg, lattice, species, coords, site_properties,
            transform_setting=None, coords_are_cartesian=False, tol=1e-5):
        """
        Generate a structure using a magnetic spacegroup. Note that only
        symmetrically distinct species, coords and magmoms should be provided.]
        All equivalent sites are generated from the spacegroup operations.

        Args:
            msg (str/list/:class:`pymatgen.symmetry.maggroups.MagneticSpaceGroup`):
                The magnetic spacegroup.
                If a string, it will be interpreted as one of the notations
                supported by MagneticSymmetryGroup, e.g., "R-3'c" or "Fm'-3'm".
                If a list of two ints, it will be interpreted as the number of
                the spacegroup in its Belov, Neronova and Smirnova (BNS) setting.
            lattice (Lattice/3x3 array): The lattice, either as a
                :class:`pymatgen.core.lattice.Lattice` or
                simply as any 2D array. Each row should correspond to a lattice
                vector. E.g., [[10,0,0], [20,10,0], [0,0,30]] specifies a
                lattice with lattice vectors [10,0,0], [20,10,0] and [0,0,30].
                Note that no attempt is made to check that the lattice is
                compatible with the spacegroup specified. This may be
                introduced in a future version.
            species ([Specie]): Sequence of species on each site. Can take in
                flexible input, including:
                i.  A sequence of element / specie specified either as string
                symbols, e.g. ["Li", "Fe2+", "P", ...] or atomic numbers,
                e.g., (3, 56, ...) or actual Element or Specie objects.

                ii. List of dict of elements/species and occupancies, e.g.,
                    [{"Fe" : 0.5, "Mn":0.5}, ...]. This allows the setup of
                    disordered structures.
            coords (Nx3 array): list of fractional/cartesian coordinates of
                each species.
            site_properties (dict): Properties associated with the sites as a
                dict of sequences, e.g., {"magmom":[5,5,5,5]}. The sequences
                have to be the same length as the atomic species and
                fractional_coords. Unlike Structure.from_spacegroup(),
                this argument is mandatory, since magnetic moment information
                has to be included. Note that the *direction* of the supplied
                magnetic moment relative to the crystal is important, even if
                the resulting structure is used for collinear calculations.
            coords_are_cartesian (bool): Set to True if you are providing
                coordinates in cartesian coordinates. Defaults to False.
            tol (float): A fractional tolerance to deal with numerical
                precision issues in determining if orbits are the same.
        """
        from pymatgen.electronic_structure.core import Magmom
        from pymatgen.symmetry.maggroups import MagneticSpaceGroup

        if 'magmom' not in site_properties:
            raise ValueError('Magnetic moments have to be defined.')
        else:
            magmoms = [Magmom(m) for m in site_properties['magmom']]

        if not isinstance(msg, MagneticSpaceGroup):
            msg = MagneticSpaceGroup(msg)

        if isinstance(lattice, Lattice):
            latt = lattice
        else:
            latt = Lattice(lattice)

        if not msg.is_compatible(latt):
            raise ValueError(
                "Supplied lattice with parameters %s is incompatible with "
                "supplied spacegroup %s!" % (latt.lengths_and_angles,
                                             msg.symbol)
            )

        if len(species) != len(coords):
            raise ValueError(
                "Supplied species and coords lengths (%d vs %d) are "
                "different!" % (len(species), len(coords))
            )

        if len(species) != len(magmoms):
            raise ValueError(
                "Supplied species and magmom lengths (%d vs %d) are "
                "different!" % (len(species), len(magmoms))
            )

        frac_coords = coords if not coords_are_cartesian else \
            lattice.get_fractional_coords(coords)

        all_sp = []
        all_coords = []
        all_magmoms = []
        all_site_properties = collections.defaultdict(list)
        for i, (sp, c, m) in enumerate(zip(species, frac_coords, magmoms)):
            cc, mm = msg.get_orbit(c, m, tol=tol)
            all_sp.extend([sp] * len(cc))
            all_coords.extend(cc)
            all_magmoms.extend(mm)
            for k, v in site_properties.items():
                if k != 'magmom':
                    all_site_properties[k].extend([v[i]] * len(cc))

        all_site_properties['magmom'] = all_magmoms

        return cls(latt, all_sp, all_coords,
                   site_properties=all_site_properties)