def get_spacegroup(self, subtrans_included) -> Spacegroup: # XXX The logic in this method needs serious cleaning up! # The setting needs to be passed as either 1 or two, not None (default) no = self._get_spacegroup_number() hm_symbol = self._get_spacegroup_name() sitesym = self._get_sitesym() setting = 1 spacegroup = 1 if sitesym is not None: subtrans = [(0.0, 0.0, 0.0)] if subtrans_included else None spacegroup = spacegroup_from_data(no=no, symbol=hm_symbol, sitesym=sitesym, subtrans=subtrans, setting=setting) elif no is not None: spacegroup = no elif hm_symbol is not None: spacegroup = hm_symbol else: spacegroup = 1 setting_std = self._get_setting() setting_name = None if '_symmetry_space_group_setting' in self: assert setting_std is not None setting = setting_std elif '_space_group_crystal_system' in self: setting_name = self['_space_group_crystal_system'] elif '_symmetry_cell_setting' in self: setting_name = self['_symmetry_cell_setting'] if setting_name: no = Spacegroup(spacegroup).no if no in rhombohedral_spacegroups: if setting_name == 'hexagonal': setting = 1 elif setting_name in ('trigonal', 'rhombohedral'): setting = 2 else: warnings.warn( 'unexpected crystal system %r for space group %r' % (setting_name, spacegroup)) # FIXME - check for more crystal systems... else: warnings.warn( 'crystal system %r is not interpreted for space group %r. ' 'This may result in wrong setting!' % (setting_name, spacegroup)) spg = Spacegroup(spacegroup, setting) if no is not None: assert int(spg) == no, (int(spg), no) return spg
def tags2atoms(tags, store_tags=False, primitive_cell=False, subtrans_included=True, fractional_occupancies=True): """Returns an Atoms object from a cif tags dictionary. See read_cif() for a description of the arguments.""" if primitive_cell and subtrans_included: raise RuntimeError( 'Primitive cell cannot be determined when sublattice translations ' 'are included in the symmetry operations listed in the CIF file, ' 'i.e. when `subtrans_included` is True.') cell_tags = [ '_cell_length_a', '_cell_length_b', '_cell_length_c', '_cell_angle_alpha', '_cell_angle_beta', '_cell_angle_gamma' ] # If any value is missing, ditch periodic boundary conditions has_pbc = True try: cell_values = [tags[ct] for ct in cell_tags] a, b, c, alpha, beta, gamma = cell_values except KeyError: has_pbc = False # Now get positions try: scaled_positions = np.array([ tags['_atom_site_fract_x'], tags['_atom_site_fract_y'], tags['_atom_site_fract_z'] ]).T except KeyError: scaled_positions = None try: positions = np.array([ tags['_atom_site_cartn_x'], tags['_atom_site_cartn_y'], tags['_atom_site_cartn_z'] ]).T except KeyError: positions = None if (positions is None) and (scaled_positions is None): raise RuntimeError('No positions found in structure') elif scaled_positions is not None and not has_pbc: raise RuntimeError('Structure has fractional coordinates but not ' 'lattice parameters') symbols = [] if '_atom_site_type_symbol' in tags: labels = tags['_atom_site_type_symbol'] else: labels = tags['_atom_site_label'] for s in labels: # Strip off additional labeling on chemical symbols m = re.search(r'([A-Z][a-z]?)', s) symbol = m.group(0) symbols.append(symbol) # Symmetry specification, see # http://www.iucr.org/resources/cif/dictionaries/cif_sym for a # complete list of official keys. In addition we also try to # support some commonly used depricated notations no = None if '_space_group.it_number' in tags: no = tags['_space_group.it_number'] elif '_space_group_it_number' in tags: no = tags['_space_group_it_number'] elif '_symmetry_int_tables_number' in tags: no = tags['_symmetry_int_tables_number'] symbolHM = None if '_space_group.Patterson_name_h-m' in tags: symbolHM = tags['_space_group.patterson_name_h-m'] elif '_symmetry_space_group_name_h-m' in tags: symbolHM = tags['_symmetry_space_group_name_h-m'] elif '_space_group_name_h-m_alt' in tags: symbolHM = tags['_space_group_name_h-m_alt'] if symbolHM is not None: symbolHM = old_spacegroup_names.get(symbolHM.strip(), symbolHM) for name in [ '_space_group_symop_operation_xyz', '_space_group_symop.operation_xyz', '_symmetry_equiv_pos_as_xyz' ]: if name in tags: sitesym = tags[name] break else: sitesym = None # The setting needs to be passed as either 1 or two, not None (default) setting = 1 spacegroup = 1 if sitesym is not None: if isinstance(sitesym, str): sitesym = [sitesym] subtrans = [(0.0, 0.0, 0.0)] if subtrans_included else None spacegroup = spacegroup_from_data(no=no, symbol=symbolHM, sitesym=sitesym, subtrans=subtrans, setting=setting) elif no is not None: spacegroup = no elif symbolHM is not None: spacegroup = symbolHM else: spacegroup = 1 kwargs = {} if store_tags: kwargs['info'] = tags.copy() if 'D' in symbols: deuterium = [symbol == 'D' for symbol in symbols] symbols = [symbol if symbol != 'D' else 'H' for symbol in symbols] else: deuterium = False setting_name = None if '_space_group_crystal_system' in tags: setting_name = tags['_space_group_crystal_system'] elif '_symmetry_cell_setting' in tags: setting_name = tags['_symmetry_cell_setting'] if setting_name: no = Spacegroup(spacegroup).no # rhombohedral systems if no in (146, 148, 155, 160, 161, 166, 167): if setting_name == 'hexagonal': setting = 1 elif setting_name in ('trigonal', 'rhombohedral'): setting = 2 else: warnings.warn( 'unexpected crystal system %r for space group %r' % (setting_name, spacegroup)) # FIXME - check for more crystal systems... else: warnings.warn( 'crystal system %r is not interpreted for space group %r. ' 'This may result in wrong setting!' % (setting_name, spacegroup)) occupancies = None if fractional_occupancies: try: occupancies = tags['_atom_site_occupancy'] # no warnings in this case kwargs['onduplicates'] = 'keep' except KeyError: pass else: try: if not np.allclose(tags['_atom_site_occupancy'], 1.): warnings.warn( 'Cif file containes mixed/fractional occupancies. ' 'Consider using `fractional_occupancies=True`') kwargs['onduplicates'] = 'keep' except KeyError: pass if has_pbc: if scaled_positions is None: _ = Atoms(symbols, positions=positions, cell=[a, b, c, alpha, beta, gamma]) scaled_positions = _.get_scaled_positions() if deuterium: numbers = np.array([atomic_numbers[s] for s in symbols]) masses = atomic_masses[numbers] masses[deuterium] = 2.01355 kwargs['masses'] = masses atoms = crystal(symbols, basis=scaled_positions, cellpar=[a, b, c, alpha, beta, gamma], spacegroup=spacegroup, occupancies=occupancies, setting=setting, primitive_cell=primitive_cell, **kwargs) else: atoms = Atoms(symbols, positions=positions, info=kwargs.get('info', None)) if occupancies is not None: # Compile an occupancies dictionary occ_dict = {} for i, sym in enumerate(symbols): occ_dict[i] = {sym: occupancies[i]} atoms.info['occupancy'] = occ_dict if deuterium: masses = atoms.get_masses() masses[atoms.numbers == 1] = 1.00783 masses[deuterium] = 2.01355 atoms.set_masses(masses) return atoms
def tags2atoms(tags, store_tags=False, primitive_cell=False, subtrans_included=True): """Returns an Atoms object from a cif tags dictionary. See read_cif() for a description of the arguments.""" if primitive_cell and subtrans_included: raise RuntimeError( 'Primitive cell cannot be determined when sublattice translations ' 'are included in the symmetry operations listed in the CIF file, ' 'i.e. when `subtrans_included` is True.') a = tags['_cell_length_a'] b = tags['_cell_length_b'] c = tags['_cell_length_c'] alpha = tags['_cell_angle_alpha'] beta = tags['_cell_angle_beta'] gamma = tags['_cell_angle_gamma'] scaled_positions = np.array([ tags['_atom_site_fract_x'], tags['_atom_site_fract_y'], tags['_atom_site_fract_z'] ]).T symbols = [] if '_atom_site_type_symbol' in tags: labels = tags['_atom_site_type_symbol'] else: labels = tags['_atom_site_label'] for s in labels: # Strip off additional labeling on chemical symbols m = re.search(r'([A-Z][a-z]?)', s) symbol = m.group(0) symbols.append(symbol) # Symmetry specification, see # http://www.iucr.org/resources/cif/dictionaries/cif_sym for a # complete list of official keys. In addition we also try to # support some commonly used depricated notations no = None if '_space_group.it_number' in tags: no = tags['_space_group.it_number'] elif '_space_group_it_number' in tags: no = tags['_space_group_it_number'] elif '_symmetry_int_tables_number' in tags: no = tags['_symmetry_int_tables_number'] symbolHM = None if '_space_group.Patterson_name_h-m' in tags: symbolHM = tags['_space_group.patterson_name_h-m'] elif '_symmetry_space_group_name_h-m' in tags: symbolHM = tags['_symmetry_space_group_name_h-m'] elif '_space_group_name_h-m_alt' in tags: symbolHM = tags['_space_group_name_h-m_alt'] if symbolHM is not None: symbolHM = old_spacegroup_names.get(symbolHM.strip(), symbolHM) for name in [ '_space_group_symop_operation_xyz', '_space_group_symop.operation_xyz', '_symmetry_equiv_pos_as_xyz' ]: if name in tags: sitesym = tags[name] break else: sitesym = None spacegroup = 1 if sitesym is not None: subtrans = [(0.0, 0.0, 0.0)] if subtrans_included else None spacegroup = spacegroup_from_data(no=no, symbol=symbolHM, sitesym=sitesym, subtrans=subtrans) elif no is not None: spacegroup = no elif symbolHM is not None: spacegroup = symbolHM else: spacegroup = 1 if store_tags: kwargs = {'info': tags.copy()} else: kwargs = {} if 'D' in symbols: deuterium = [symbol == 'D' for symbol in symbols] symbols = [symbol if symbol != 'D' else 'H' for symbol in symbols] else: deuterium = False atoms = crystal(symbols, basis=scaled_positions, cellpar=[a, b, c, alpha, beta, gamma], spacegroup=spacegroup, primitive_cell=primitive_cell, **kwargs) if deuterium: masses = atoms.get_masses() masses[atoms.numbers == 1] = 1.00783 masses[deuterium] = 2.01355 atoms.set_masses(masses) return atoms
def tags2atoms(tags, store_tags=False, primitive_cell=False, subtrans_included=True): """Returns an Atoms object from a cif tags dictionary. See read_cif() for a description of the arguments.""" if primitive_cell and subtrans_included: raise RuntimeError( 'Primitive cell cannot be determined when sublattice translations ' 'are included in the symmetry operations listed in the CIF file, ' 'i.e. when `subtrans_included` is True.') a = tags['_cell_length_a'] b = tags['_cell_length_b'] c = tags['_cell_length_c'] alpha = tags['_cell_angle_alpha'] beta = tags['_cell_angle_beta'] gamma = tags['_cell_angle_gamma'] scaled_positions = np.array([tags['_atom_site_fract_x'], tags['_atom_site_fract_y'], tags['_atom_site_fract_z']]).T symbols = [] if '_atom_site_type_symbol' in tags: labels = tags['_atom_site_type_symbol'] else: labels = tags['_atom_site_label'] for s in labels: # Strip off additional labeling on chemical symbols m = re.search(r'([A-Z][a-z]?)', s) symbol = m.group(0) symbols.append(symbol) # Symmetry specification, see # http://www.iucr.org/resources/cif/dictionaries/cif_sym for a # complete list of official keys. In addition we also try to # support some commonly used depricated notations no = None if '_space_group.it_number' in tags: no = tags['_space_group.it_number'] elif '_space_group_it_number' in tags: no = tags['_space_group_it_number'] elif '_symmetry_int_tables_number' in tags: no = tags['_symmetry_int_tables_number'] symbolHM = None if '_space_group.Patterson_name_h-m' in tags: symbolHM = tags['_space_group.patterson_name_h-m'] elif '_symmetry_space_group_name_h-m' in tags: symbolHM = tags['_symmetry_space_group_name_h-m'] elif '_space_group_name_h-m_alt' in tags: symbolHM = tags['_space_group_name_h-m_alt'] if symbolHM is not None: symbolHM = old_spacegroup_names.get(symbolHM.strip(), symbolHM) for name in ['_space_group_symop_operation_xyz', '_space_group_symop.operation_xyz', '_symmetry_equiv_pos_as_xyz']: if name in tags: sitesym = tags[name] break else: sitesym = None spacegroup = 1 if sitesym is not None: subtrans = [(0.0, 0.0, 0.0)] if subtrans_included else None spacegroup = spacegroup_from_data( no=no, symbol=symbolHM, sitesym=sitesym, subtrans=subtrans) elif no is not None: spacegroup = no elif symbolHM is not None: spacegroup = symbolHM else: spacegroup = 1 if store_tags: kwargs = {'info': tags.copy()} else: kwargs = {} if 'D' in symbols: deuterium = [symbol == 'D' for symbol in symbols] symbols = [symbol if symbol != 'D' else 'H' for symbol in symbols] else: deuterium = False atoms = crystal(symbols, basis=scaled_positions, cellpar=[a, b, c, alpha, beta, gamma], spacegroup=spacegroup, primitive_cell=primitive_cell, **kwargs) if deuterium: masses = atoms.get_masses() masses[atoms.numbers == 1] = 1.00783 masses[deuterium] = 2.01355 atoms.set_masses(masses) return atoms