def test_current_mm_idx_property(self): self._sample._reset(magdefs=True, cell=True, muon=True, sym=True) self._sample.cell = Atoms(symbols=['C'], scaled_positions=[[0, 0, 0]], cell=[[3., 0, 0], [0, 3., 0], [0, 0, 3.]]) self._sample.new_mm() self._sample.mm.k = np.array([0, 0, 1.]) self.assertEqual(self._sample.current_mm_idx, 0) self._sample.new_mm() self._sample.mm.k = np.array([0, 0, 2.]) self.assertEqual(self._sample.current_mm_idx, 1) self._sample.new_mm() self._sample.mm.k = np.array([0, 0, 3.]) self.assertEqual(self._sample.current_mm_idx, 2) self._sample.current_mm_idx = 0 self.assertEqual(self._sample.current_mm_idx, 0) np.testing.assert_array_equal(self._sample.mm.k, np.array([0, 0, 1.])) with self.assertRaises(IndexError): self._sample.current_mm_idx = 3 with self.assertRaises(IndexError): self._sample.current_mm_idx = -1 self.assertEqual(self._sample.current_mm_idx, 0)
def test_add_muon_property(self): self._sample._reset(cell=True, muon=True, sym=True, magdefs=True) with self.assertRaises(CellError): self._sample.add_muon([0, 0, 0]) self._set_a_cell() with self.assertRaises(TypeError): self._sample.add_muon('0 0 0') with self.assertRaises(ValueError): self._sample.add_muon([0, 0, 0, 0]) with self.assertRaises(ValueError): self._sample.add_muon(np.array([0, 0, 0, 0])) self._sample.add_muon([0, 0, 0]) np.testing.assert_array_equal(self._sample.muons[0], np.zeros(3)) self._sample.add_muon([1, 1, 1]) np.testing.assert_array_equal(self._sample.muons[1], np.ones(3)) self._sample.add_muon([1, 1, 1], cartesian=True) np.testing.assert_array_equal(self._sample.muons[2], np.ones(3) / 3.) a = 4.0 # some lattice constant b = a / 2 self._sample.cell = Atoms(symbols=['Au'], positions=[0, 0, 0], cell=[(0, b, b), (b, 0, b), (b, b, 0)], pbc=True) self._sample.add_muon([1., 1., 1.], cartesian=True) np.testing.assert_array_equal(self._sample.muons[3], np.ones(3) / 4.) self._sample.add_muon([.5, .5, .5], cartesian=False) self._sample.add_muon([2., 2., 2.], cartesian=True) np.testing.assert_array_equal(self._sample.muons[4], self._sample.muons[5])
def test_mm_property(self): self._sample._reset(cell=True, magdefs=True, muon=True, sym=True) with self.assertRaises(MagDefError): self._sample.mm with self.assertRaises(CellError): self._sample.mm = MM(19) # randomly large number self._sample._reset(magdefs=True) self._set_a_cell() with self.assertRaises(TypeError): self._sample.mm = 1 self._sample._reset(magdefs=True, cell=True, muon=True, sym=True) self._sample.cell = Atoms(symbols=['C'], scaled_positions=[[0, 0, 0]], cell=[[3., 0, 0], [0, 3., 0], [0, 0, 3.]]) with self.assertRaises(MagDefError): self._sample.mm = MM(198) # randomly large number self._sample.mm = MM(1)
def _set_a_cell(self): self._sample.cell = Atoms(symbols=['Co'], scaled_positions=[[0, 0, 0]], cell=[[3., 0, 0], [0, 3., 0], [0, 0, 3.]])
def run_muesr( self, frac_coords, contact_field ): """ This function use MUESR to calculated local field contributions Parameters ---------- frac_coords : numpy.ndarray fractional coordinates (with muon) contact_field : numpy.ndarray contact vector in Tesla Returns ------- total dipolar lorentz contact """ #print('contact field =', contact_field) cell = self.cell_parameter symbols = self.get_species moments = self.get_magnetic_moments # Define structure in MuESR atoms = Atoms(symbols = symbols, scaled_positions = frac_coords, cell = cell, pbc=True) s = Sample() s.cell = atoms s.new_mm() # s.mm.k is already 0 s.mm.fc = moments # muon site position in frac_coords if self.if_equivalent_sites: muon_site = frac_coords[self.mu_f] else: muon_site = frac_coords[-1] # add muon sites s.add_muon(muon_site) if self.if_equivalent_sites: # to reduce compuational load. However, the supercell lattice parameters # are almost identical n=30 sc = [n,n,n] else: n=1000 sc = list(self.relax_structure.lattice.abc) sc =[int(np.ceil(n/latt)) for latt in sc] r = locfield(s,'s', sc, find_largest_sphere(s,sc), nnn = 2, rcont = 10.0) B_d_prime = np.zeros([len(s.muons),3]) B_d = np.zeros([len(s.muons),3]) B_l = np.zeros([len(s.muons),3]) B_c = np.zeros([len(s.muons),3]) B_t = np.zeros([len(s.muons),3]) for i in range(len(s.muons)): B_d[i] = r[i].D B_l[i] = r[i].L B_c[i] = np.array(contact_field) B_d_prime[i] = r[i].D + r[i].L B_t[i] = B_d_prime[i] + B_c[i] return B_t[0], B_d[0], B_l[0], B_c[0],
def load_sample(filename="", fileobj=None): """ This function load a sample from a file in YAML format. :param str filename: the filename used to store data. :param file fileobj: an optional file object. If specified, this supersede the filename input. :return: a sample object :rtype: :py:class:`~Sample` object or None :raises: ValueError, FileNotFoundError, IsADirectoryError """ # fail if YAML is not available if not have_yaml: warnings.warn("Warning, YAML python package not present!") return sample = Sample() data = {} if fileobj is None: if filename == "": raise ValueError("Specify filename or File object") with open(filename, 'r') as f: data = load(f, Loader=Loader) else: data = load(fileobj, Loader=Loader) if not (type(data) is dict): raise ValueError('Invalid data file. (problems with YAML?)') if data is None: raise ValueError('Invalid/empty data file. (problems with YAML?)') if 'Name' in data.keys(): sample.name = str(data['Name']) if 'Lattice' in data.keys(): l = data['Lattice'] spos = None cpos = None if 'ScaledPositions' in l.keys(): spos = np.array(l['ScaledPositions']) elif 'CartesianPositions' in l.keys(): cpos = np.array(l['CartesianPositions']) cell = None if 'Cell' in l.keys(): cell = np.array(l['Cell']) symbols = None if 'Symbols' in l.keys(): symbols = l['Symbols'] if (cell is None) or (symbols is None): warnings.warn('Cell not loaded!', RuntimeWarning) else: if not spos is None: sample.cell = Atoms(symbols=symbols, scaled_positions=spos, cell=cell, pbc=True) elif not cpos is None: sample.cell = Atoms(symbols=symbols, positions=cpos, cell=cell, pbc=True) else: warnings.warn('Cell not loaded!', RuntimeWarning) else: warnings.warn('Cell not loaded!', RuntimeWarning) if 'Muon' in data.keys(): m = data['Muon'] if 'Positions' in m: for p in m['Positions']: sample.add_muon(p) else: warnings.warn('Muon positions not loaded!', RuntimeWarning) else: warnings.warn('Muon positions not loaded!', RuntimeWarning) if 'Symmetry' in data.keys(): s = data['Symmetry'] if ('Number' in s.keys()) and \ ('Symbol' in s.keys()) and \ ('Rotations' in s.keys()) and \ ('Translations' in s.keys()): sample.sym = spacegroup_from_data( s['Number'], s['Symbol'], rotations=np.array(s['Rotations']), translations=np.array(s['Translations'])) else: warnings.warn('Symmetry not loaded.', RuntimeWarning) else: warnings.warn('Symmetry not loaded!', RuntimeWarning) if 'MagneticOrders' in data.keys(): m = data['MagneticOrders'] if len(m) > 0: msize = int(m['Size']) for mo in m['Orders']: if 'lattice' in mo.keys(): n = MM(msize, \ np.array(mo['lattice'])) else: n = MM(msize) sample.mm = n sample.mm.k = np.array(mo['k']) sample.mm.phi = np.array(mo['phi']) if 'desc' in mo.keys(): sample.mm.desc = str(mo['desc']) rfcs, ifcs = np.hsplit(np.array(mo['fc']), 2) if mo['format'].lower() in ['bohr-cartesian', 'b-c']: sample.mm.fcCart = (rfcs + 1.j * ifcs) elif mo['format'].lower() in ['bohr/angstrom-lattic', 'b/a-l']: sample.mm.fcLattBMA = (rfcs + 1.j * ifcs) elif mo['format'].lower() in ['bohr-lattice', 'b-l']: sample.mm.fcLattBM = (rfcs + 1.j * ifcs) else: raise ValueError( 'Invalid Fourier Components format specifier in YAML file.' ) else: warnings.warn('Magnetic definitions not loaded!', RuntimeWarning) else: warnings.warn('Magnetic definitions not loaded!', RuntimeWarning) return sample
def crystal(symbols=None, basis=None, spacegroup=1, setting=1, cell=None, cellpar=None, ab_normal=(0, 0, 1), a_direction=None, size=(1, 1, 1), onduplicates='warn', symprec=0.001, pbc=True, **kwargs): """Create an Atoms instance for a conventional unit cell of a space group. Parameters: symbols : str | sequence of str | sequence of Atom | Atoms Element symbols of the unique sites. Can either be a string formula or a sequence of element symbols. E.g. ('Na', 'Cl') and 'NaCl' are equivalent. Can also be given as a sequence of Atom objects or an Atoms object. basis : list of scaled coordinates Positions of the unique sites corresponding to symbols given either as scaled positions or through an atoms instance. Not needed if *symbols* is a sequence of Atom objects or an Atoms object. spacegroup : int | string | Spacegroup instance Space group given either as its number in International Tables or as its Hermann-Mauguin symbol. setting : 1 | 2 Space group setting. cell : 3x3 matrix Unit cell vectors. cellpar : [a, b, c, alpha, beta, gamma] Cell parameters with angles in degree. Is not used when `cell` is given. ab_normal : vector Is used to define the orientation of the unit cell relative to the Cartesian system when `cell` is not given. It is the normal vector of the plane spanned by a and b. a_direction : vector Defines the orientation of the unit cell a vector. a will be parallel to the projection of `a_direction` onto the a-b plane. size : 3 positive integers How many times the conventional unit cell should be repeated in each direction. onduplicates : 'keep' | 'replace' | 'warn' | 'error' Action if `basis` contain symmetry-equivalent positions: 'keep' - ignore additional symmetry-equivalent positions 'replace' - replace 'warn' - like 'keep', but issue an UserWarning 'error' - raises a SpacegroupValueError symprec : float Minimum "distance" betweed two sites in scaled coordinates before they are counted as the same site. pbc : one or three bools Periodic boundary conditions flags. Examples: True, False, 0, 1, (1, 1, 0), (True, False, False). Default is True. Keyword arguments: All additional keyword arguments are passed on to the Atoms constructor. Currently, probably the most useful additional keyword arguments are `info`, `constraint` and `calculator`. Examples: Two diamond unit cells (space group number 227) >>> diamond = crystal('C', [(0,0,0)], spacegroup=227, ... cellpar=[3.57, 3.57, 3.57, 90, 90, 90], size=(2,1,1)) >>> ase.view(diamond) # doctest: +SKIP A CoSb3 skutterudite unit cell containing 32 atoms >>> skutterudite = crystal(('Co', 'Sb'), ... basis=[(0.25,0.25,0.25), (0.0, 0.335, 0.158)], ... spacegroup=204, cellpar=[9.04, 9.04, 9.04, 90, 90, 90]) >>> len(skutterudite) 32 """ sg = Spacegroup(spacegroup, setting) #if (not isinstance(symbols, str) and # hasattr(symbols, '__getitem__') and # len(symbols) > 0 ): # symbols = Atoms(symbols) #if isinstance(symbols, Atoms): # basis = symbols # symbols = basis.get_chemical_symbols() #if isinstance(basis, Atoms): # basis_coords = basis.get_scaled_positions() # if cell is None and cellpar is None: # cell = basis.cell # if symbols is None: # symbols = basis.get_chemical_symbols() #else: basis_coords = np.array(basis, dtype=float, copy=False, ndmin=2) sites, kinds = sg.equivalent_sites(basis_coords, onduplicates=onduplicates, symprec=symprec) symbols = parse_symbols(symbols) symbols = [symbols[i] for i in kinds] if cell is None: cell = cellpar_to_cell(cellpar, ab_normal, a_direction) atoms = Atoms(symbols, scaled_positions=sites, cell=cell, pbc=pbc) if isinstance(basis, Atoms): for name in basis.arrays: if not atoms.has(name): array = basis.get_array(name) atoms.new_array(name, [array[i] for i in kinds], dtype=array.dtype, shape=array.shape[1:]) if size != (1, 1, 1): atoms = atoms.repeat(size) return atoms, sg
def get_simple_supercell(sample, multi): """ This function creates a simple supercell by expanding the unit cell in a, b and c directions. """ # Scaled positions within the frame, i.e., create a supercell that # is made simply to multiply the input cell. unitcell = sample.cell if type(multi) is np.ndarray: multi = multi.tolist() if type(multi) is list: if len(multi) == 3: try: multi = [int(x) for x in multi] except: raise TypeError('Cannot convert multi to int') if multi[0] <= 0 or multi[1] <= 0 or multi[2] <= 0: raise ValueError('Supercell values must be strictly positive.') else: # everything is fine! pass else: raise ValueError('multi must be a 3D vector!') else: raise TypeError('multi must me list or numpy array of integers' + ' (automatically converted)') have_mag_structure = True FC = None K = None PHI = None try: FC = sample.mm.fc K = sample.mm.k PHI = sample.mm.phi except MagDefError: have_mag_structure = False positions = unitcell.get_scaled_positions() numbers = unitcell.get_atomic_numbers() masses = unitcell.get_masses() lattice = unitcell.get_cell() # these lists are used to strore new values positions_multi = [] numbers_multi = [] masses_multi = [] if not have_mag_structure: magmoms_multi = None else: magmoms_multi = [] for l, pos in enumerate(positions): if numbers[l] == 0: # Check again if muon in there! raise RuntimeError # This shuld never happen! continue for k in range(multi[2]): for j in range(multi[1]): for i in range(multi[0]): positions_multi.append([(pos[0] + i) / multi[0], (pos[1] + j) / multi[1], (pos[2] + k) / multi[2]]) numbers_multi.append(numbers[l]) masses_multi.append(masses[l]) if have_mag_structure: c = np.cos( 2.0 * np.pi * (np.dot(K, [float(i), float(j), float(k)]) + PHI[l])) s = np.sin( 2.0 * np.pi * (np.dot(K, [float(i), float(j), float(k)]) + PHI[l])) sk = np.real(FC[l]) isk = np.imag(FC[l]) m = np.zeros(3) m = c * sk + s * isk #print "Norma: " , np.linalg.norm(m) magmoms_multi.append(m) return Atoms(numbers=numbers_multi, masses=masses_multi, magmoms=magmoms_multi, scaled_positions=positions_multi, cell=np.dot(np.diag(multi), lattice), pbc=True)