def __init__(self, potential): """ Builds a PotInfo component class. Parameters ---------- potential : Potential, str or DataModelDict A Potential record object or DataModelDict contents for a Potential record. This prodives the information to link the Potential to the Action. """ if isinstance(potential, Potential.Potential): # Extract relevant properties from the Potential object self.__id = potential.id self.__key = potential.key self.__dois = [] for citation in potential.citations: try: self.__dois.append(citation.doi) except: pass self.__fictional = potential.fictional self.__elements = potential.elements self.__othername = potential.othername else: # Extract relevant properties from potential record contents model = DM(potential).find('potential') self.__id = model['id'] self.__key = model['key'] self.__dois = model.aslist('doi') felements = model.aslist('fictional-element') oelements = model.aslist('other-element') elements = model.aslist('element') if len(felements) > 0: assert len(elements) == 0 self.__fictional = True self.__elements = felements else: assert len(elements) > 0 self.__fictional = False self.__elements = elements if len(oelements) > 0: assert len(oelements) == 1 self.__othername = oelements[0] else: self.__othername = None
def load(self, model): model = DM(model).find('request') self.date = model['date'] self.comment = model.get('comment', None) self.__systems = [] for system in model.aslist('system'): self.add_system(model=DM([('system', system)]))
def load_model(self, model, name=None): """ Loads record contents from a given model. Parameters ---------- model : str or DataModelDict The model contents of the record to load. name : str, optional The name to assign to the record. Often inferred from other attributes if not given. """ super().load_model(model, name=name) req = DM(model).find('request') self.date = req['date'] self.comment = req.get('comment', None) self.__systems = [] for system in req.aslist('system'): self.add_system(model=DM([('system',system)])) if name is not None: self.name = name else: elements = [] for system in self.systems: elements.extend(system.elements) self.name = f'{self.date} {" ".join(elements)}'
def load(self, model): model = DM(model).find('action') self.date = model['date'] self.type = model['type'] self.comment = model.get('comment', None) self.__potentials = [] for potential in model.aslist('potential'): self.potentials.append(PotInfo(DM([('potential', potential)])))
def __init__(self, potential): if isinstance(potential, Potential): self.__id = potential.id self.__key = potential.key self.__dois = [] for citation in potential.citations: self.__dois.append(citation.doi) self.__fictional = potential.fictional self.__elements = potential.elements self.__othername = potential.othername elif isinstance(potential, DM): model = DM(potential).find('potential') self.__id = model['id'] self.__key = model['key'] self.__dois = model.aslist('doi') felements = model.aslist('fictional-element') oelements = model.aslist('other-element') elements = model.aslist('element') if len(felements) > 0: assert len(elements) == 0 self.__fictional = True self.__elements = felements else: assert len(elements) > 0 self.__fictional = False self.__elements = elements if len(oelements) > 0: assert len(oelements) == 1 self.__othername = oelements[0] else: self.__othername = None else: raise TypeError('Invalid potential content')
def __init__(self, natoms=None, atype=None, pos=None, prop=None, model=None, safecopy=False, **kwargs): """ Class initializer. Parameters ========== natoms : int, optional The number of atoms. If not given, will be inferred from other parameters if possible, or set to 1 if not possible. atype : int or list/ndarray of int, optional The integer atomic types to assign to all atoms. Default is to set all atypes to 1. pos : list/ndarray of float, optional The atomic positions to assign to all atoms. Default is to set each atom's position to [0,0,0]. model : str or DataModelDict, optional File path or content of a JSON/XML data model containing all atom information. Cannot be given with any other parameters. prop : dict, optional Dictionary containing all per-atom properties. Can be used instead of atype, pos, and kwargs. This is for backwards compatibility support with atomman version 1. safecopy : bool, optional Flag indicating if values are to be copied before setting. For property values given as numpy arrays, direct setting (False, default) may result in the Atoms' property pointing to the original numpy array. Using safecopy=True deep copies the property values before setting to avoid this. Note that safecopy=True may be considerably slower for large numbers of atoms and/or properties. kwargs : any All additional key/value pairs are assigned as properties. Returns ======= Atoms The Atoms object. """ # Check for model if model is not None: try: assert natoms is None assert atype is None assert pos is None assert prop is None assert len(kwargs) == 0 except: raise ValueError( 'model cannot be given with any other parameters') # Extract natoms and properties from data model model = DM(model).find('atoms') natoms = model['natoms'] prop = OrderedDict() for propmodel in model.aslist('property'): prop[propmodel['name']] = uc.value_unit(propmodel['data']) # Check for prop dictionary if prop is not None: if atype is not None and pos is not None and len(kwargs) > 0: raise ValueError( 'prop dict cannot be given with keyword properties') # Divide prop into keyword arguments atype = prop.pop('atype', None) pos = prop.pop('pos', None) kwargs = prop # Check atype parameter values if atype is not None: atype = np.asarray(atype, dtype='uint64') # Handle single atype if atype.ndim == 0: natoms_atype = 1 # Handle list of atype elif atype.ndim == 1: natoms_atype = atype.shape[0] else: raise ValueError('Only one atype per atom allowed') else: atype = np.array([1], dtype='uint64') natoms_atype = 1 # Check pos parameter values if pos is not None: pos = np.asarray(pos, dtype='float64') # Handle single pos if pos.ndim == 1: if pos.shape[0] == 3: natoms_pos = 1 else: raise ValueError('pos per atom must be 3-dimensional') # Handle list of pos elif pos.ndim == 2: if pos.shape[1] == 3: natoms_pos = pos.shape[0] else: raise ValueError('pos per atom must be 3-dimensional') else: raise ValueError('too many dimensions for pos') else: pos = np.zeros((1, 3), dtype='float64') natoms_pos = 1 # Check natoms parameter values if natoms is not None: natoms = int(natoms) if ((natoms_atype == 1 or natoms_atype == natoms) and (natoms_pos == 1 or natoms_pos == natoms)): pass else: raise ValueError( 'natoms and length of atype/pos not compatible') else: if natoms_atype == natoms_pos: natoms = natoms_atype elif natoms_atype == 1: natoms = natoms_pos elif natoms_pos == 1: natoms = natoms_atype else: raise ValueError('lengths of atype and pos not compatible') # Initialize underlying private class attributes super(Atoms, self).__setattr__('_Atoms__natoms', natoms) super(Atoms, self).__setattr__('_Atoms__view', Atoms.PropertyDict(self)) super(Atoms, self).__setattr__('_Atoms__dir', deepcopy(dir(self))) # Set properties if safecopy: self.view['atype'] = deepcopy(atype) self.view['pos'] = deepcopy(pos) for key, value in kwargs.items(): self.view[key] = deepcopy(value) else: self.view['atype'] = atype self.view['pos'] = pos for key, value in kwargs.items(): self.view[key] = value
def structure_static(xml_lib_dir): calc_name = 'structure_static' groups = os.path.join(xml_lib_dir, '*', calc_name, '*') error_dict = DataModelDict() for group_dir in glob.iglob(groups): if os.path.isdir(group_dir): calc_dir, group_name = os.path.split(group_dir) pot_name = os.path.basename(os.path.dirname(calc_dir)) print pot_name try: with open(os.path.join(calc_dir, 'badlist.txt'), 'r') as f: badlist = f.read().split() except: badlist = [] data = DataModelDict() for sim_path in glob.iglob(os.path.join(group_dir, '*.xml')): sim_file = os.path.basename(sim_path) sim_name = sim_file[:-4] if sim_name in badlist: continue with open(sim_path) as f: sim = DataModelDict(f)['calculation-crystal-phase'] if 'error' in sim: badlist.append(sim_name) error_message = sim['error'] error = 'Unknown error' for line in error_message.split('\n'): if 'Error' in line: error = line error_dict.append(error, sim_name) continue try: cell = sim['relaxed-atomic-system']['cell'] except: tar_gz_path = sim_path[:-4] + '.tar.gz' if os.isfile(tar_gz_path): error_dict.append('Unknown error', sim_name) continue data.append('key', sim.get('calculation-id', '')) data.append('file', sim['crystal-info'].get('artifact', '')) data.append('symbols', '_'.join(sim['crystal-info'].aslist('symbols'))) data.append('Temperature (K)', sim['phase-state']['temperature']['value']) data.append('Pressure (GPa)', sim['phase-state']['pressure']['value']) cell = cell[cell.keys()[0]] data.append('Ecoh (eV)', sim['cohesive-energy']['value'] ) if 'a' in cell: data.append('a (A)', cell['a']['value']) else: data.append('a (A)', '') if 'b' in cell: data.append('b (A)', cell['b']['value']) else: data.append('b (A)', '') if 'c' in cell: data.append('c (A)', cell['c']['value']) else: data.append('c (A)', '') C_dict = {} for C in sim['elastic-constants'].iteraslist('C'): C_dict[C['ij']] = C['stiffness']['value'] data.append('C11 (GPa)', C_dict.get('1 1', '')) data.append('C22 (GPa)', C_dict.get('2 2', '')) data.append('C33 (GPa)', C_dict.get('3 3', '')) data.append('C12 (GPa)', C_dict.get('1 2', '')) data.append('C13 (GPa)', C_dict.get('1 3', '')) data.append('C23 (GPa)', C_dict.get('2 3', '')) data.append('C44 (GPa)', C_dict.get('4 4', '')) data.append('C55 (GPa)', C_dict.get('5 5', '')) data.append('C66 (GPa)', C_dict.get('6 6', '')) if len(data.keys()) > 0: with open(os.path.join(calc_dir, 'structure_static_'+group_name+'.csv'), 'w') as f: f.write(','.join(data.keys())+'\n') for i in xrange(len(data.aslist('key'))): f.write(','.join([str(data.aslist(k)[i]) for k in data.keys()]) + '\n') with open(os.path.join(calc_dir, 'badlist.txt'), 'w') as f: for bad in badlist: f.write(bad+'\n')
def __init__(self, atoms=None, box=None, pbc=None, scale=False, symbols=None, masses=None, model=None, safecopy=False): """ Initialize a System by joining an am.Atoms and am.Box instance. Parameters ---------- atoms : atomman.Atoms, optional The underlying Atoms object to build system around. box : atomman.Box, optional The underlying box object to build system around. pbc : tuple or list of bool, optional Indicates which of the dimensions related to the three box vectors are periodic. Default value is (True, True, True). scale : bool, optional If True, atoms.pos will be scaled relative to the box. Default value is False. symbols : tuple, optional A list of the element symbols for each atom atype. If len(symbols) is less than natypes, then missing values will be set to None. Default sets list with all None values. masses : tuple, optional A list of the masses for each atom atype. If len(symbols) is less than natypes, then missing values will be set to None. Default sets list with all None values. model : str or DataModelDict, optional File path or content of a JSON/XML data model containing all system information. Cannot be given with atoms, box or scale. safecopy : bool, optional Flag indicating if values are to be copied before setting. For values given as objects, direct setting (False, default) may result in the System pointing to the original object. Using safecopy=True deep copies the objects before setting to avoid this. Note that safecopy=True may be considerably slower for large numbers of atoms and/or properties. Returns ======= System The System object. """ # Check for model if model is not None: try: assert atoms is None assert box is None assert scale is False except: raise ValueError( 'model cannot be given with atoms, box or scale parameters' ) # Load data model model = DM(model).find('atomic-system') # Extract values from model box = Box(model=model) atoms = Atoms(model=model) if pbc is None: pbc = model['periodic-boundary-condition'] if symbols is None: symbols = tuple(model.aslist('atom-type-symbol')) if masses is None: masses = tuple(model.aslist('atom-type-mass')) # Interpret given/missing parameters else: # Set default atoms or deepcopy if atoms is None: atoms = Atoms() elif safecopy: atoms = deepcopy(atoms) # Set default box or deepcopy if box is None: box = Box() elif safecopy: box = deepcopy(box) # Set default pbc if pbc is None: pbc = (True, True, True) # Set default masses if masses is None: masses = [] else: masses = aslist(masses) # Set default symbols if symbols is None: symbols = [None for i in range(len(masses))] else: symbols = aslist(symbols) # Check data types if not isinstance(atoms, Atoms): raise TypeError('Invalid atoms type') if not isinstance(box, Box): raise TypeError('Invalid box type') if not isinstance(scale, bool): raise TypeError('Invalid scale type') # Set properties self.__atoms = atoms self.__box = box self.pbc = pbc self.__transformation = np.identity(3) self.symbols = symbols self.masses = masses # Scale pos if needed if scale is True: self.atoms_prop('pos', value=self.atoms.pos, scale=True) # Scale model properties if needed if model is not None: for prop in model['atoms'].aslist('property'): if prop['data'].get('unit', None) == 'scaled': self.atoms.view[prop['name']] = self.unscale( self.atoms.view[prop['name']]) # Set atoms indexer self.__atoms_ix = System._AtomsIndexer(self)
def __init__(self, atoms=None, box=None, pbc=None, scale=False, symbols=None, model=None): """ Initialize a System by joining an am.Atoms and am.Box instance. Parameters ---------- atoms : atomman.Atoms, optional The underlying Atoms object to build system around. box : atomman.Box, optional The underlying box object to build system around. pbc : tuple or list of bool, optional Indicates which of the dimensions related to the three box vectors are periodic. Default value is (True, True, True). scale : bool, optional If True, atoms.pos will be scaled relative to the box. Default value is False. symbols : tuple, optional A list of the element symbols for each atom atype. If len(symbols) is less than natypes, then missing values will be set to None. Default value is (,), i.e. all values set to None. model : str or DataModelDict, optional File path or content of a JSON/XML data model containing all system information. Cannot be given with atoms, box or scale. """ # Check for model if model is not None: try: assert atoms is None assert box is None assert scale is False except: raise ValueError('model cannot be given with atoms, box or scale parameters') # Load data model model = DM(model).find('atomic-system') # Extract values from model box = Box(model=model) atoms = Atoms(model=model) if pbc is None: pbc = model['periodic-boundary-condition'] if symbols is None: symbols = tuple(model.aslist('atom-type-symbol')) else: # Set default values if atoms is None: atoms = Atoms() if box is None: box = Box() if pbc is None: pbc= (True, True, True) if symbols is None: symbols=() # Check data types if not isinstance(atoms, Atoms): raise TypeError('Invalid atoms type') if not isinstance(box, Box): raise TypeError('Invalid box type') if not isinstance(scale, bool): raise TypeError('Invalid scale type') # Set properties self.__atoms = atoms self.__box = box self.pbc = pbc self.__transformation = np.identity(3) if isinstance(symbols, stringtype): symbols = (symbols,) assert len(symbols) <= self.natypes self.__symbols = tuple(symbols) # Scale pos if needed if scale is True: self.atoms_prop('pos', value=atoms.pos, scale=True) # Scale model properties if needed if model is not None: for prop in model['atoms'].aslist('property'): if prop['data'].get('unit', None) == 'scaled': self.atoms.view[prop['name']] = self.unscale(self.atoms.view[prop['name']]) # Set atoms indexer self.__atoms_ix = System._AtomsIndexer(self)