def get_electric_field_gradients_tensors(self, diag=True):

        if diag:
            search_string = 'Electric field gradients after diagonalization (V/A^2)'
            jump = 5
        else:
            search_string = 'Electric field gradients (V/A^2)'
            jump = 4

        if not self.complete:
            raise Exception(
                "Run does not yet have EFG information - not completed")

        tensor_start_index = self.get_line_indices_containing_string(
            search_string)[-1] + jump + -1

        efg_tensors = []

        for N in range(self.get_number_of_atoms()):
            atomic_efg_tensor = []

            tensor_start_index += 1

            line = self.lines[tensor_start_index]
            row_number_list = su.get_number_list_from_string(line)

            efg_tensors.append(row_number_list[1:])

        return efg_tensors
    def final_forces_list(self):
        """
		Returns list of forces - one for each x, y, z component of each atom, ordered by poscar position.
		"""

        if not self.complete:
            raise Exception("Run not yet completed - cannot get forces list")

        forces_start_indices = self.get_line_indices_containing_string(
            Outcar.forces_string)

        if len(forces_start_indices) == 0:
            raise Exception("No set of forces found in completed outcar file")

        forces_start_index = forces_start_indices[-1] + 2

        final_forces_list = []

        for line_index in range(self.get_number_of_atoms()):
            line = self.lines[forces_start_index + line_index]

            row_number_list = su.get_number_list_from_string(line)

            if not len(row_number_list) == 6:
                raise Exception(
                    "Error reading row from forces data. Length should be 6 but is not. Row number list looks like",
                    row_number_list)

            final_forces_list += row_number_list[3:6]

        if len(final_forces_list) != self.get_number_of_atoms() * 3:
            raise Exception("Incorrect number of forces obtained:",
                            final_forces_list)

        return final_forces_list
    def get_born_effective_charge_tensor(self):
        """
		Returns an Nx3x3 tensor, where N is the number of atoms in the POSCAR of the calculation. The Born Effective Charge Tensor looks like:

		BORN EFFECTIVE CHARGES (in e, cummulative output)
		 -------------------------------------------------
		 ion    1
		    1     2.55248     0.00000     0.00001
		    2     0.00000     2.55247     0.00000
		    3     0.00001     0.00000     2.59358   <---- this last component is indexed by [0][2][2] and represents the change in the z-component of polarization with z-displacement of atom 1
		 ion    2
		    1     7.24494     0.00000     0.00009
		    2     0.00000     7.24494     0.00001
		    3     0.00010     0.00001     6.01323
		 ion    3
		    1    -5.77788     0.00000    -0.00004
		    2     0.00000    -2.00260     0.00000
		    3    -0.00009     0.00000    -1.89826
		    				.
		    				.
		    				.
		ion     N

		"""

        if not self.complete:
            raise Exception(
                "Run does not yet have a born effective charge tensor - not completed"
            )

        tensor_start_indices = self.get_line_indices_containing_string(
            Outcar.born_effective_charge_tensor_string)

        if len(tensor_start_indices) == 0:
            raise Exception(
                "No born effective charge tensor found in completed outcar file"
            )

        tensor_start_index = tensor_start_indices[-1] - 1

        born_effective_charge_tensor = []

        for N in range(self.get_number_of_atoms()):
            atomic_tensor = []

            tensor_start_index += 4

            for line in self.lines[tensor_start_index:tensor_start_index + 3]:
                row_number_list = su.get_number_list_from_string(line)[1:]

                if not len(row_number_list) == 3:
                    raise Exception(
                        "Error reading row from born effect charge tensor. Length should be 3 but is not. Row number list looks like",
                        row_number_list)

                atomic_tensor.append(row_number_list)

            born_effective_charge_tensor.append(atomic_tensor)

        return born_effective_charge_tensor
    def get_dielectric_tensor(self):
        """
		Returns a 3x3 dielectric tensor with component (0, 0) as eps_xx and so forth.
		"""

        if not self.complete:
            raise Exception(
                "Run does not yet have a dielectric tensor - not completed")

        tensor_start_indices = self.get_line_indices_containing_string(
            Outcar.dielectric_tensor_string)

        if len(tensor_start_indices) == 0:
            raise Exception(
                "No dielectric tensor found in completed outcar file")

        tensor_start_index = tensor_start_indices[-1] + 2

        dielectric_tensor = []

        for line in self.lines[tensor_start_index:tensor_start_index + 3]:
            row_number_list = su.get_number_list_from_string(line)

            if not len(row_number_list) == 3:
                raise Exception(
                    "Error reading row from dielectric tensor. Length should be 3 but is not. Row number list looks like",
                    row_number_list)

            dielectric_tensor.append(row_number_list)

        return dielectric_tensor
    def get_symmetrized_chemical_shift_tensor(self):
        """
		Returns an Nx3x3 tensor, where N is the number of atoms in the POSCAR of the calculation. The Born Effective Charge Tensor looks like:

		 SYMMETRIZED TENSORS
		 ion    1
		        548.029048          0.000000          0.000000
		          0.000000        548.029048          0.000000
		          0.000000          0.000000        548.029048
		 ion    2
		        548.029048          0.000000          0.000000
		          0.000000        548.029048          0.000000
		          0.000000          0.000000        548.029048
		 ion    3
			...

		"""

        if not self.complete:
            raise Exception(
                "Run does not yet have a chemical shift tensor - not completed"
            )

        tensor_start_indices = self.get_line_indices_containing_string(
            Outcar.chemical_shift_string)

        if len(tensor_start_indices) == 0:
            raise Exception(
                "No chemical shift tensor found in completed outcar file")

        tensor_start_index = tensor_start_indices[-1] - 2

        chemical_shift_tensor = []

        for N in range(self.get_number_of_atoms()):
            atomic_tensor = []

            tensor_start_index += 4

            for line in self.lines[tensor_start_index:tensor_start_index + 3]:
                row_number_list = su.get_number_list_from_string(line)

                if not len(row_number_list) == 3:
                    raise Exception(
                        "Error reading row from chemical shift tensor. Length should be 3 but is not. Row number list looks like",
                        row_number_list)

                atomic_tensor.append(row_number_list)

            chemical_shift_tensor.append(atomic_tensor)

        return chemical_shift_tensor
    def final_stresses_list(self):
        """
		Returns list of stresses (in eV) - one for each x, y, z component of each atom, ordered by poscar position. Note, the negative of the vasp output is
		taken in order to make this output an externally applied stress. Positive stress means pulling in tension.

		To convert to actual pressure units, divide by the volume of the cell

		The order is standardized to [XX          YY          ZZ          YZ          XZ          XY]
		"""

        if not self.complete:
            raise Exception("Run not yet completed - cannot get stresses list")

        stresses_start_indices = self.get_line_indices_containing_string(
            Outcar.stresses_string)

        if len(stresses_start_indices) == 0:
            raise Exception(
                "No set of stresses found in completed outcar file")

        stresses_start_index = stresses_start_indices[-1] + 13

        line = self.lines[stresses_start_index]

        line = ' '.join(line.split(' ')[3:])

        final_stresses_list = su.get_number_list_from_string(line)

        if not len(final_stresses_list) == 6:
            raise Exception(
                "Error reading row from stresses data. Length should be 6 but is not. Row number list looks like",
                final_stresses_list)

        new_stresses = [-1.0 * x for x in final_stresses_list]

        return [
            new_stresses[0], new_stresses[1], new_stresses[2], new_stresses[4],
            new_stresses[5], new_stresses[3]
        ]
    def get_isotropic_chemical_shifts(self):
        """
		Returns a list of isotropic chemical shifts, one for each atomic species in the poscar.

		 ---------------------------------------------------------------------------------
		  CSA tensor (J. Mason, Solid State Nucl. Magn. Reson. 2, 285 (1993))
		 ---------------------------------------------------------------------------------
		             EXCLUDING G=0 CONTRIBUTION             INCLUDING G=0 CONTRIBUTION
		         -----------------------------------   -----------------------------------
		  ATOM    ISO_SHIFT        SPAN        SKEW     ISO_SHIFT        SPAN        SKEW
		 ---------------------------------------------------------------------------------
		  (absolute, valence only)
		     1     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		     2     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		     3     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		     4     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		     5     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		     6     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		     7     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		     8     548.0290      0.0000      0.0000      434.1470      0.0000      0.0000
		 ---------------------------------------------------------------------------------
		  (absolute, valence and core)			   ***this is the column*** <-------------------------------
		     1    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		     2    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		     3    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		     4    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		     5    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		     6    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		     7    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		     8    -289.8550      0.0000      0.0000     -405.3448      0.0000      0.0000
		 ---------------------------------------------------------------------------------
		  IF SPAN.EQ.0, THEN SKEW IS ILL-DEFINED
		 ---------------------------------------------------------------------------------

		"""

        if not self.complete:
            raise Exception(
                "Run does not yet have chemical shift information - not completed"
            )

        tensor_start_indices = self.get_line_indices_containing_string(
            Outcar.isotropic_chemical_shift_string)

        if len(tensor_start_indices) == 0:
            raise Exception(
                "No chemical shift information found in completed outcar file")

        tensor_start_index = tensor_start_indices[-1]

        chemical_shift_values = []

        for N in range(self.get_number_of_atoms()):
            atomic_tensor = []

            tensor_start_index += 1

            line = self.lines[tensor_start_index]
            row_number_list = su.get_number_list_from_string(line)
            iso_shift = row_number_list[4]

            chemical_shift_values.append(iso_shift)

        return chemical_shift_values
	def __init__(self, xml_file_path):

		self.tree = ET.parse(xml_file_path)

		root = self.tree.getroot()

		self.atom_types = []
		
		for arr in root.find('atominfo'):
			if arr.attrib.has_key('name') and arr.attrib['name'] == 'atoms':

				for atoms in arr.find('set'):
					for atom in atoms:
						if not su.string_represents_integer(atom.text):
							self.atom_types.append(atom.text.strip())

		self.positions = []
		self.lattices = []
		self.forces = []

		#get forces and atom positions
		for calculation in root.findall('calculation'):

			for structure in calculation.findall('structure'):

				for v in structure.find('crystal'):
					if v.attrib.has_key('name') and v.attrib['name'] == 'basis':
						self.lattices.append([su.get_number_list_from_string(v[i].text) for i in range(len(v))])

				for v in structure.findall('varray'):

					if v.attrib.has_key('name') and v.attrib['name'] == 'positions':
						self.positions.append([su.get_number_list_from_string(v[i].text) for i in range(len(v))])

			for v in calculation:

				if v.attrib.has_key('name') and v.attrib['name'] == 'forces':
					
					self.forces.append([su.get_number_list_from_string(v[i].text) for i in range(len(v))])


		#make the list of structures, one for each ionic step
		self.structures = []

		num_ionic_steps = len(self.positions)
		num_atoms = len(self.atom_types)

		if len(self.lattices) != num_ionic_steps or len(self.forces) != num_ionic_steps:
			raise Exception("Inconsistent number of data.")

		for i in range(num_ionic_steps):

			sites = []

			if len(self.positions[i]) != num_atoms or len(self.forces[i]) != num_atoms:
				raise Exception("Not a consistent atom count in data.")


			for j in range(num_atoms):
				site = Site({'position': self.positions[i][j], 'coordinate_mode': 'Direct', 'type': self.atom_types[j], 'force': self.forces[i][j]}) ##########Assumes direct coords!!!!

				sites.append(site)

			self.structures.append(Structure(lattice=self.lattices[i], sites=SiteCollection(sites)))




# num_neighbors = 140

# vxml = VaspXML('C:/Users/Tom/Desktop/cu_force_256.xml')


# output = File()

# xml_structures = vxml.structures


# count = 0
# for structure in xml_structures:
# 	count += 1

# 	print "Structure count is " + str(count) + " out of " + str(len(xml_structures))

# 	samples = StructureAnalyzer.get_force_potential_samples(structure=structure, N_max=1, cutoff_fraction=0.9)

# 	for sample in samples:
# 		output += " ".join([str(round(x, 5)) for x in sample[0:num_neighbors*3+3]])

# output.write_to_path('C:/Users/Tom/Desktop/out.txt')