Beispiel #1
0
def get_rawsoap(frame,soapstr,nocenters, global_species, rc, nmax, lmax,awidth,
                centerweight,cutoff_transition_width,
                 cutoff_dexp, cutoff_scale,cutoff_rate):
    frame = ase2qp(frame)
    frame.set_cutoff(rc)
    frame.calc_connect()
    global_speciesstr = '{'+re.sub('[\[,\]]', '', str(global_species))+'}'
    nspecies = len(global_species)

    spInFrame = np.unique(frame.get_atomic_numbers())
    # makes sure that the nocenters is propely adapted to the species present in the frame
    nocenterInFrame = []
    for nocenter in nocenters:
        if nocenter in spInFrame:
            nocenterInFrame.append(nocenter)

    centers = []
    ncentres = len(spInFrame) - len(nocenterInFrame)
    for z in spInFrame:
        if z in nocenterInFrame:
            continue
        centers.append(str(z))
    centers = '{'+' '.join(centers)+'} '

    soapstr2 = soapstr.substitute(nspecies=nspecies, ncentres=ncentres,cutoff_rate=cutoff_rate,
                                  species=global_speciesstr, centres=centers,
                                  cutoff_transition_width=cutoff_transition_width,
                                 rc=rc, nmax=nmax, lmax=lmax, awidth=awidth,cutoff_dexp=cutoff_dexp,
                                  cutoff_scale=cutoff_scale,centerweight=centerweight)
    desc = descriptors.Descriptor(soapstr2)
    soap = desc.calc(frame, grad=False)['descriptor']
    return soap
Beispiel #2
0
    def __init__(self,
                 sn,
                 tracer_atomic_number=None,
                 soap_params={},
                 verbose=True):

        # Make a copy of the structure
        self._structure = qp.Atoms(sn.static_structure)
        # Add a tracer
        if tracer_atomic_number is None:
            tracer_atomic_number = sn.structure.get_atomic_numbers()[
                sn.mobile_mask][0]

        self.tracer_atomic_number = tracer_atomic_number

        self._structure.add_atoms((0.0, 0.0, 0.0), tracer_atomic_number)
        self._tracer_index = len(self._structure) - 1

        # Create the descriptor
        soap_opts = dict(DEFAULT_SOAP_PARAMS)
        soap_opts.update(soap_params)
        soap_cmd_line = ["soap"]
        # User options
        for opt in soap_opts:
            soap_cmd_line.append("{}={}".format(opt, soap_opts[opt]))
        # Stuff that's the same no matter what
        soap_cmd_line.append("n_Z=1")  #always one tracer
        soap_cmd_line.append("Z={{{}}}".format(self.tracer_atomic_number))

        self._soaper = descriptors.Descriptor(" ".join(soap_cmd_line))

        self.verbose = verbose
Beispiel #3
0
    def calculate(self, structure, **kwargs):

        atoms = scale_structure(
            structure,
            scaling_type=self.atoms_scaling,
            atoms_scaling_cutoffs=self.atoms_scaling_cutoffs)

        #Define descritpor
        desc = descriptors.Descriptor(self.descriptor_options)

        #Define structure as quippy Atoms object
        filename = str(atoms.info['label']) + '.xyz'
        ase_write(filename, atoms, format='xyz')
        struct = quippy_Atoms(filename)
        struct.set_pbc(self.p_b_c)

        #Remove redundant files that have been created
        if os.path.exists(filename):
            os.remove(filename)
        if os.path.exists(filename + '.idx'):
            os.remove(filename + '.idx')

        #Compute SOAP descriptor
        struct.set_cutoff(desc.cutoff())
        struct.calc_connect()
        SOAP_descriptor = desc.calc(struct)['descriptor']

        if self.average_over_permuations:
            #average over different orders
            SOAP_proto_averaged = np.zeros(SOAP_descriptor.size)
            SOAP_proto_copy = SOAP_descriptor
            for i in range(self.number_averages):
                np.random.shuffle(SOAP_proto_copy)
                SOAP_proto_averaged = np.add(SOAP_proto_averaged,
                                             SOAP_proto_copy.flatten())
            SOAP_proto_averaged = np.array(
                [x / float(self.number_averages) for x in SOAP_proto_averaged])
            SOAP_descriptor = SOAP_proto_averaged

        if self.average:
            SOAP_descriptor = SOAP_descriptor.flatten(
            )  # if get averaged LAE, then default output shape is (1,316), hence flatten()

        descriptor_data = dict(descriptor_name=self.name,
                               descriptor_info=str(self),
                               SOAP_descriptor=SOAP_descriptor)

        structure.info['descriptor'] = descriptor_data

        return structure
    def calculate(self, structure, **kwargs):

        # HACK to get right PBC for 2D materials and Nanotubes
        # use pbc as specified in the structure ITSELF
        self.p_b_c = structure.get_pbc()

        # the following code gives errors!
        #if (self.p_b_c).any()==False:
        #    structure.cell = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]

        #if (self.p_b_c).all()==False:
        #    structure.cell = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]

        if type(self.p_b_c) == list or type(self.p_b_c) == np.ndarray:
            for idx, p_b_c_component in enumerate(self.p_b_c):
                if p_b_c_component == False:
                    #structure.cell[self.p_b_c[idx]] = [0.0,0.0,0.0]
                    structure.cell[idx] = [0.0, 0.0, 0.0]
        elif self.p_b_c == False:
            structure.set_cell([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0],
                                [0.0, 0.0, 0.0]])
        else:
            raise ValueError("Format of cell not known.")

        structure.set_pbc(self.p_b_c)
        #print(self.p_b_c)
        logger.info("Structure: " + str(structure))
        # Important for  avoiding crash of polycrystal code
        # Uncommented part: look at TOTAL number of atoms. Now do it element-specific (i.e. each species needs to be there min_atoms # times, otherwise this species will not be considered and treated as vacancy)
        """
        if len(structure)<self.min_atoms:
            
            soap_desc = np.full(self.shape_soap, np.nan)
            descriptor_data = dict(descriptor_name=self.name, descriptor_info=str(self), SOAP_descriptor=soap_desc)
            structure.info['descriptor'] = descriptor_data
            return structure 
        """
        # get all atomic numbers and the unique values
        atomic_numbers = structure.get_atomic_numbers()
        atomic_numbers_unique = list(set(atomic_numbers))

        occurences_species = Counter(atomic_numbers)
        species_to_delete = []
        for species in atomic_numbers_unique:
            if occurences_species[species] < self.min_atoms:
                species_to_delete.append(species)
        del structure[[
            atom.index for atom in structure
            if atom.number in species_to_delete
        ]]

        if len(structure
               ) == 0:  # case that had to delete all species, return nan
            logger.info(
                "Structure empty after deleting all under-represented species")
            soap_desc = np.full(self.shape_soap, np.nan)
            descriptor_data = dict(descriptor_name=self.name,
                                   descriptor_info=str(self),
                                   SOAP_descriptor=soap_desc)
            structure.info['descriptor'] = descriptor_data
            return structure

        if self.return_binary_descriptor:
            """
            if self.scale_element_sensitive:
                pass
            else:
                raise ValueError('Need to scale element-sensitive for binary descriptor!')
                return []
            """
            atomic_numbers = list(set(structure.get_atomic_numbers()))
            all_descriptors = []
            for Z in atomic_numbers:
                for species_Z in atomic_numbers:
                    #
                    #if Z==species_Z and len(structure[structure.get_atomic_numbers()==species_Z])<=1:
                    #    all_descriptors.append(np.full(316, 0.0))
                    #    continue
                    #
                    n_Z = 1
                    n_species = 1
                    #print(Z, species_Z)
                    atoms = scale_structure(
                        structure,
                        scaling_type=self.atoms_scaling,
                        atoms_scaling_cutoffs=self.atoms_scaling_cutoffs,
                        extrinsic_scale_factor=self.extrinsic_scale_factor,
                        element_sensitive=self.scale_element_sensitive,
                        central_atom_species=Z,
                        neighbor_atoms_species=species_Z,
                        constrain_nn_distances=self.constrain_nn_distances)

                    #Define descritpor - all options stay untouched, i.e., as provided by the intial call, but the species parameter are changed
                    descriptor_options = 'soap '+'cutoff='+str(self.cutoff)+' l_max='+str(self.l_max)+' n_max='+str(self.n_max)+' atom_sigma='+str(self.atom_sigma)+\
                                         ' n_Z='+str(n_Z)+' Z={'+str(Z)+'} n_species='+str(n_species)+' species_Z={'+str(species_Z)+'} central_weight='+str(self.central_weight)+' average='+str(self.average)
                    desc = descriptors.Descriptor(descriptor_options)

                    if self.version == 'py3':
                        SOAP_descriptor = desc.calc(atoms)['data'].flatten()
                    else:
                        #Define structure as quippy Atoms object
                        #filename=str(atoms.info['label'])+'.xyz'
                        #ase_write(filename,atoms,format='xyz')
                        #struct=quippy_Atoms(filename)
                        from quippy import Atoms as quippy_Atoms
                        struct = quippy_Atoms(
                            atoms
                        )  # Seems to work fine like this. (rather than creating xyz file first)
                        struct.set_pbc(self.p_b_c)

                        #Remove redundant files that have been created
                        #if os.path.exists(filename):
                        #    os.remove(filename)
                        #if os.path.exists(filename+'.idx'):
                        #    os.remove(filename+'.idx')

                        #Compute SOAP descriptor
                        struct.set_cutoff(desc.cutoff())
                        struct.calc_connect()
                        SOAP_descriptor = desc.calc(struct)['descriptor']
                        #print 'SOAP '+str(SOAP_descriptor.flatten().shape)

                    if any(np.isnan(SOAP_descriptor.flatten())):
                        #plt.plot(SOAP_descriptor.flatten())
                        #print np.nan_to_num(SOAP_descriptor, copy=True)
                        #plt.plot(np.nan_to_num(SOAP_descriptor, copy=True).flatten())
                        raise ValueError(
                            'Nan value encountered in SOAP descriptor.')

                    if self.average_over_permuations:
                        #average over different orders
                        SOAP_proto_averaged = np.zeros(SOAP_descriptor.size)
                        SOAP_proto_copy = SOAP_descriptor
                        # To do: SOAP_proto_copy is not a real copy...
                        # The right way: http://henry.precheur.org/python/copy_list.html
                        # or just a = ..., b = np.array(a)
                        for i in range(self.number_averages):
                            np.random.shuffle(SOAP_proto_copy)
                            SOAP_proto_averaged = np.add(
                                SOAP_proto_averaged, SOAP_proto_copy.flatten())
                        SOAP_proto_averaged = np.array([
                            x / float(self.number_averages)
                            for x in SOAP_proto_averaged
                        ])
                        SOAP_descriptor = SOAP_proto_averaged

                    #if self.average:
                    #    SOAP_descriptor=SOAP_descriptor.flatten() # if get averaged LAE, then default output shape is (1,316), hence flatten()
                    all_descriptors.append(SOAP_descriptor.flatten())

            #if len(all_descriptors)==0: # if choose to skip environments with only one atom --> all_descriptors may be empty. That's why append nan array to avoid
            # mistakes eg in make_strided_pattern_matching_dataset when structure.info['descriptor'][desc_metadata][:] = np.nan is used!
            #    all_descriptors.append(np.full(self.shape_soap, np.nan))

            if self.average_binary_descriptor:
                all_descriptors = np.mean(np.array(all_descriptors), axis=0)
                descriptor_data = dict(descriptor_name=self.name,
                                       descriptor_info=str(self),
                                       SOAP_descriptor=all_descriptors)
            else:
                descriptor_data = dict(
                    descriptor_name=self.name,
                    descriptor_info=str(self),
                    SOAP_descriptor=np.array(all_descriptors))
            structure.info['descriptor'] = descriptor_data
            return structure
Beispiel #5
0
dist2 = 2

positions = np.ones((6, 3), dtype=float) * volume * 0.5
#Carbon is at the center of the cell
positions[1, 0] += dist
positions[2, 0] -= dist
positions[3:6, :] = positions[0:3, :]
positions[3:6, 1] += dist2

test = Atoms(numbers=atoms_species,
             positions=positions[:, :],
             cell=[volume, volume, volume],
             pbc=[True, True, True])

desc = descriptors.Descriptor(
    "soap cutoff=4.5 l_max=4 n_max=4 atom_sigma=0.5 n_Z=2 Z={6 8} n_species=2 species_Z={6 8}"
)

data_desc = desc.calc(test)

data = data_desc["data"]

plt.plot(data[0, :])
plt.plot(data[1, :])
plt.plot(data[2, :])
plt.show()

plt.plot(data[3, :])
plt.plot(data[4, :])
plt.plot(data[5, :])
plt.show()