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
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
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
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()