Пример #1
0
    def scale(self, factor: float) -> LammpsData:
        """
        Scales the charge in of the in self.data and returns a new one. TODO: check if non-destructive

        Args:
            factor: The charge scaling factor

        Returns:
            A recreated LammpsData obj
        """
        items = {}
        items["box"] = self.data.box
        items["masses"] = self.data.masses
        atoms = self.data.atoms.copy(deep=True)
        atoms["q"] = atoms["q"] * factor
        assert np.around(atoms.q.sum(), decimals=self.precision) == np.around(
            self.data.atoms.q.sum() * factor, decimals=self.precision)
        digit_count = 0
        for q in atoms["q"]:
            rounded = self.count_significant_figures(q)
            if rounded > digit_count:
                digit_count = rounded
        print("No. of significant figures to output for charges: ",
              digit_count)
        items["atoms"] = atoms
        items["atom_style"] = self.data.atom_style
        items["velocities"] = self.data.velocities
        items["force_field"] = self.data.force_field
        items["topology"] = self.data.topology
        return LammpsData(**items)
Пример #2
0
    def write_data_file(self, organism, job_dir_path, composition_space):
        """
        Writes the file (called in.data) containing the structure that LAMMPS
        reads.

        Args:
            organism: the Organism whose structure to write

            job_dir_path: the path the job directory (as a string) where the
                file will be written

            composition_space: the CompositionSpace of the search
        """

        # get xhi, yhi and zhi from the lattice vectors
        lattice_coords = organism.cell.lattice.matrix
        xhi = lattice_coords[0][0]
        yhi = lattice_coords[1][1]
        zhi = lattice_coords[2][2]
        box_size = [[0.0, xhi], [0.0, yhi], [0.0, zhi]]

        # get xy, xz and yz from the lattice vectors
        xy = lattice_coords[1][0]
        xz = lattice_coords[2][0]
        yz = lattice_coords[2][1]

        # get a list of the elements from the lammps input script to
        # preserve their order of appearance
        num_atoms = len(composition_space.get_all_elements())
        with open(self.input_script, 'r') as f:
            lines = f.readlines()
        for line in lines:
            if 'pair_coeff' in line:
                element_symbols = line.split()[-1*num_atoms:]
        all_elements = []
        for symbol in element_symbols:
            all_elements.append(Element(symbol))

        # get the dictionary of atomic masses - set the atom types to the order
        # of their appearance in the lammps input script
        atomic_masses_dict = {}
        for i in range(len(all_elements)):
            atomic_masses_dict[all_elements[i].symbol] = [
                i + 1, float(all_elements[i].atomic_mass)]

        # get the atoms data
        atoms_data = LammpsData.get_atoms_data(
            organism.cell, atomic_masses_dict, set_charge=True)

        # make a LammpsData object
        lammps_data = LammpsData(box_size, atomic_masses_dict.values(),
                                 atoms_data)

        # write the data to a file
        # This method doesn't write the tilts, so we have to add those. It also
        # writes the molecule id of each atom, so we have to remove those
        lammps_data.write_data_file(job_dir_path + '/in.data')

        # read the in.data file as a list of strings
        with open(job_dir_path + '/in.data', 'r') as f:
            lines = f.readlines()

        # find the location to insert the tilts
        insertion_index = 0
        for line in lines:
            if 'zhi' in line:
                insertion_index = lines.index(line) + 1

        # build the string containing the tilts and add it
        tilts_string = str(xy) + ' ' + str(xz) + ' ' + str(yz) + ' xy xz yz\n'
        lines.insert(insertion_index, tilts_string)

        # get the index of the line where the atoms info starts
        atoms_index = 0
        for line in lines:
            if 'Atoms' in line:
                atoms_index = lines.index(line) + 2

        # remove the the molecule id's
        for i in range(len(organism.cell.sites)):
            split_line = lines[atoms_index + i].split()
            del split_line[1]
            modified_line = ''
            for item in split_line:
                modified_line = modified_line + item + ' '
            modified_line = modified_line + '\n'
            lines[atoms_index + i] = modified_line
        lines[-1] = lines[-1] + '\n'

        # overwrite the in.data file with the new contents, including the tilts
        with open(job_dir_path + '/in.data', 'w') as f:
            for line in lines:
                f.write('%s' % line)