Get same branch dipole moment (convert_to_muC_per_cm2=False)
        or polarization for given polarization data (convert_to_muC_per_cm2=True).

        Polarization is a lattice vector, meaning it is only defined modulo the
        quantum of polarization:

            P = P_0 + \\sum_i \\frac{n_i e R_i}{\\Omega}

        where n_i is an integer, e is the charge of the electron in microCoulombs,
        R_i is a lattice vector, and \\Omega is the unit cell volume in cm**3
        (giving polarization units of microCoulomb per centimeter**2).

        The quantum of the dipole moment in electron Angstroms (as given by VASP) is:

            \\sum_i n_i e R_i

        where e, the electron charge, is 1 and R_i is a lattice vector, and n_i is an integer.

        Given N polarization calculations in order from nonpolar to polar, this algorithm
        minimizes the distance between adjacent polarization images. To do this, it
        constructs a polarization lattice for each polarization calculation using the
        pymatgen.core.structure class and calls the get_nearest_site method to find the
        image of a given polarization lattice vector that is closest to the previous polarization
        lattice vector image.

        Note, using convert_to_muC_per_cm2=True and all_in_polar=True calculates the "proper
        polarization" (meaning the change in polarization does not depend on the choice of
        polarization branch) while convert_to_muC_per_cm2=True and all_in_polar=False calculates
        the "improper polarization" (meaning the change in polarization does depend on the choice
        of branch). As one might guess from the names. We recommend calculating the "proper
        polarization".

        convert_to_muC_per_cm2: convert polarization from electron * Angstroms to
            microCoulomb per centimeter**2
        all_in_polar: convert polarization to be in polar (final structure) polarization lattice

def get_same_branch_polarization_data(self, convert_to_muC_per_cm2=True, all_in_polar=True):
        """
        Get same branch dipole moment (convert_to_muC_per_cm2=False)
        or polarization for given polarization data (convert_to_muC_per_cm2=True).

        Polarization is a lattice vector, meaning it is only defined modulo the
        quantum of polarization:

            P = P_0 + \\sum_i \\frac{n_i e R_i}{\\Omega}

        where n_i is an integer, e is the charge of the electron in microCoulombs,
        R_i is a lattice vector, and \\Omega is the unit cell volume in cm**3
        (giving polarization units of microCoulomb per centimeter**2).

        The quantum of the dipole moment in electron Angstroms (as given by VASP) is:

            \\sum_i n_i e R_i

        where e, the electron charge, is 1 and R_i is a lattice vector, and n_i is an integer.

        Given N polarization calculations in order from nonpolar to polar, this algorithm
        minimizes the distance between adjacent polarization images. To do this, it
        constructs a polarization lattice for each polarization calculation using the
        pymatgen.core.structure class and calls the get_nearest_site method to find the
        image of a given polarization lattice vector that is closest to the previous polarization
        lattice vector image.

        Note, using convert_to_muC_per_cm2=True and all_in_polar=True calculates the "proper
        polarization" (meaning the change in polarization does not depend on the choice of
        polarization branch) while convert_to_muC_per_cm2=True and all_in_polar=False calculates
        the "improper polarization" (meaning the change in polarization does depend on the choice
        of branch). As one might guess from the names. We recommend calculating the "proper
        polarization".

        convert_to_muC_per_cm2: convert polarization from electron * Angstroms to
            microCoulomb per centimeter**2
        all_in_polar: convert polarization to be in polar (final structure) polarization lattice
        """

        p_elec, p_ion = self.get_pelecs_and_pions()
        p_tot = p_elec + p_ion
        p_tot = np.array(p_tot)

        lattices = [s.lattice for s in self.structures]
        volumes = np.array([s.lattice.volume for s in self.structures])

        L = len(p_elec)

        e_to_muC = -1.6021766e-13
        cm2_to_A2 = 1e16
        units = 1.0 / np.array(volumes)
        units *= e_to_muC * cm2_to_A2

        # convert polarizations and lattice lengths prior to adjustment
        if convert_to_muC_per_cm2 and not all_in_polar:
            # Convert the total polarization
            p_tot = np.multiply(units.T[:, np.newaxis], p_tot)
            # adjust lattices
            for i in range(L):
                lattice = lattices[i]
                l, a = lattice.lengths_and_angles
                lattices[i] = Lattice.from_lengths_and_angles(
                    np.array(l) * units.ravel()[i], a)
        #  convert polarizations to polar lattice
        elif convert_to_muC_per_cm2 and all_in_polar:
            abc = [lattice.abc for lattice in lattices]
            abc = np.array(abc)  # [N, 3]
            p_tot /= abc  # e * Angstroms to e
            p_tot *= abc[-1] / volumes[-1] * e_to_muC * cm2_to_A2  # to muC / cm^2
            for i in range(L):
                lattice = lattices[-1]  # Use polar lattice
                l, a = lattice.lengths_and_angles
                lattices[i] = Lattice.from_lengths_and_angles(
                    np.array(l) * units.ravel()[-1], a)  # Use polar units (volume)


        d_structs = []
        sites = []
        for i in range(L):
            l = lattices[i]
            frac_coord = np.divide(np.array([p_tot[i]]),
                                   np.array([l.a, l.b, l.c]))
            d = PolarizationLattice(l, ["C"], [np.array(frac_coord).ravel()])
            d_structs.append(d)
            site = d[0]
            if i == 0:
                # Adjust nonpolar polarization to be closest to zero.
                # This is compatible with both a polarization of zero or a half quantum.
                prev_site = [0, 0, 0]
            else:
                prev_site = sites[-1].coords
            new_site = d.get_nearest_site(prev_site, site)
            sites.append(new_site[0])

        adjust_pol = []
        for s, d in zip(sites, d_structs):
            l = d.lattice
            adjust_pol.append(
                np.multiply(s.frac_coords, np.array([l.a, l.b, l.c])).ravel())
        adjust_pol = np.array(adjust_pol)

        return adjust_pol