def populate(self, structure, prec=1e-5, maxiter=200, verbose=False,
                 precond=True, vsym=True):
        """
        Takes a partially populated tensor, and populates the non-zero
        entries according to the following procedure, iterated until
        the desired convergence (specified via prec) is achieved.

        1. Find non-zero entries
        2. Symmetrize the tensor with respect to crystal symmetry and
           (optionally) voigt symmetry
        3. Reset the non-zero entries of the original tensor

        Args:
            structure (structure object)
            prec (float): precision for determining a non-zero value
            maxiter (int): maximum iterations for populating the tensor
            verbose (bool): whether to populate verbosely
            precond (bool): whether to precondition by cycling through
                all symmops and storing new nonzero values, default True
            vsym (bool): whether to enforce voigt symmetry, defaults
                to True
        """
        if precond:
            # Generate the guess from populated
            sops = SpacegroupAnalyzer(structure).get_symmetry_operations()
            guess = Tensor(np.zeros(self.shape))
            mask = abs(self) > prec
            guess[mask] = self[mask]

            def merge(old, new):
                gmask = np.abs(old) > prec
                nmask = np.abs(new) > prec
                new_mask = np.logical_not(gmask)*nmask
                avg_mask = gmask*nmask
                old[avg_mask] = (old[avg_mask] + new[avg_mask]) / 2.
                old[new_mask] = new[new_mask]
            if verbose:
                print("Preconditioning for {} symmops".format(len(sops)))
            for sop in sops:
                rot = guess.transform(sop)
                # Store non-zero entries of new that weren't previously
                # in the guess in the guess
                merge(guess, rot)
            if verbose:
                print("Preconditioning for voigt symmetry".format(len(sops)))
            if vsym:
                v = guess.voigt
                perms = list(itertools.permutations(range(len(v.shape))))
                for perm in perms:
                    vtrans = np.transpose(v, perm)
                    merge(v, vtrans)
                guess = Tensor.from_voigt(v)
        else:
            guess = np.zeros(self.shape)

        assert guess.shape == self.shape, "Guess must have same shape"
        converged = False
        test_new, test_old = [guess.copy()]*2
        for i in range(maxiter):
            test_new = test_old.fit_to_structure(structure)
            if vsym:
                test_new = test_new.voigt_symmetrized
            diff = np.abs(test_old - test_new)
            converged = (diff < prec).all()
            if converged:
                break
            test_new[mask] = self[mask]
            test_old = test_new
            if verbose:
                print("Iteration {}: {}".format(i, np.max(diff)))
        if not converged:
            max_diff = np.max(np.abs(self - test_new))
            warnings.warn("Warning, populated tensor is not converged "
                          "with max diff of {}".format(max_diff))
        return self.__class__(test_new)