def mongo_atoms_doc(atoms): """Return a dictionary of an Atoms object.""" d = OrderedDict(atoms=[{'symbol': atom.symbol, 'position': json.loads(encode(atom.position)), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': json.loads(encode(atom.momentum)), 'magmom': atom.magmom} for atom in atoms], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # redundant information for search convenience. d['natoms'] = len(atoms) cell = atoms.get_cell() if cell is not None and np.linalg.det(cell) > 0: d['volume'] = atoms.get_volume() d['mass'] = sum(atoms.get_masses()) syms = atoms.get_chemical_symbols() d['chemical_symbols'] = list(set(syms)) d['symbol_counts'] = {sym: syms.count(sym) for sym in syms} d['spacegroup'] = spglib.get_spacegroup(atoms) return json.loads(encode(d))
def test_jsonio(): """Test serialization of ndarrays and other stuff.""" from datetime import datetime import numpy as np import io from ase.io.jsonio import encode, decode, read_json, write_json assert decode(encode(np.int64(42))) == 42 c = np.array([0.1j]) assert (decode(encode(c)) == c).all() fd = io.StringIO() obj1 = {'hello': 'world'} write_json(fd, obj1) fd.seek(0) obj2 = read_json(fd) print(obj1) print(obj2) for obj in [0.5 + 1.5j, datetime.now()]: s = encode(obj) o = decode(s) print(obj) print(s) print(obj) assert obj == o, (obj, o, s)
def mongo_atoms_doc(atoms): """Return a dictionary of an Atoms object.""" d = OrderedDict(atoms=[{ 'symbol': atom.symbol, 'position': json.loads(encode(atom.position)), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': json.loads(encode(atom.momentum)), 'magmom': atom.magmom } for atom in atoms], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # redundant information for search convenience. d['natoms'] = len(atoms) cell = atoms.get_cell() if cell is not None and np.linalg.det(cell) > 0: d['volume'] = atoms.get_volume() d['mass'] = sum(atoms.get_masses()) syms = atoms.get_chemical_symbols() d['chemical_symbols'] = list(set(syms)) d['symbol_counts'] = {sym: syms.count(sym) for sym in syms} d['spacegroup'] = spglib.get_spacegroup(atoms) return json.loads(encode(d))
def test_jsonio_atoms(): def assert_equal(atoms1, atoms2): assert atoms1 == atoms2 assert set(atoms1.arrays) == set(atoms2.arrays) for name in atoms1.arrays: assert np.array_equal(atoms1.arrays[name], atoms2.arrays[name]), name atoms = bulk('Ti') print('atoms', atoms) txt = encode(atoms) print('encoded', txt) atoms1 = decode(txt) print('decoded', atoms1) txt1 = encode(atoms1) assert txt == txt1 assert_equal(atoms, atoms1) BeH = molecule('BeH') assert BeH.has('initial_magmoms') new_BeH = decode(encode(BeH)) assert_equal(BeH, new_BeH) assert new_BeH.has('initial_magmoms') from ase.constraints import FixAtoms atoms = bulk('Ti') atoms.constraints = FixAtoms(indices=[0]) newatoms = decode(encode(atoms)) c1 = atoms.constraints c2 = newatoms.constraints assert len(c1) == len(c2) == 1 # Can we check constraint equality somehow? # Would make sense for FixAtoms assert np.array_equal(c1[0].index, c2[0].index)
def _make_atoms_dict(atoms): ''' Convert an ase.Atoms object into a dictionary for json storage. Arg: atoms ase.Atoms object Returns: atoms_dict A dictionary with various atoms information stored ''' atoms_dict = OrderedDict( atoms=[{ 'symbol': atom.symbol, 'position': json.loads(encode(atom.position)), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': json.loads(encode(atom.momentum)), 'magmom': atom.magmom } for atom in atoms], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # Redundant information for search convenience. atoms_dict['natoms'] = len(atoms) cell = atoms.get_cell() atoms_dict['mass'] = sum(atoms.get_masses()) syms = atoms.get_chemical_symbols() atoms_dict['chemical_symbols'] = list(set(syms)) atoms_dict['symbol_counts'] = {sym: syms.count(sym) for sym in syms} atoms_dict['spacegroup'] = spglib.get_spacegroup(atoms) if cell is not None and np.linalg.det(cell) > 0: atoms_dict['volume'] = atoms.get_volume() return json.loads(encode(atoms_dict))
def _old2new(self, values): if self.version == 4: return values # should be ok for reading by convert.py script if len(values) == 26: extra = decode(values[25]) return values[:-1] + (encode(extra['key_value_pairs']), encode(extra['data'])) elif len(values) == 29: keywords = decode(values[-4]) kvp = decode(values[-3]) kvp.update(dict((keyword, 1) for keyword in keywords)) return values[:-4] + (encode(kvp),) + values[-2:] assert False
def test_jsonio_atoms_info(): atoms_ref = bulk('Ti') atoms_ref.info['any_name_for_a_dictionary'] = {0: 'anything'} text = encode(atoms_ref) atoms = decode(text) key = next(iter(atoms.info['any_name_for_a_dictionary'])) assert isinstance(key, int)
def sync(self): """Write data dictionary. Write bool, int, float, complex and str data, shapes and dtypes for ndarrays.""" self._write_header() assert self.shape[0] == 0 i = self.fd.tell() s = encode(self.data).encode() writeint(self.fd, len(s)) self.fd.write(s) n = len(self.offsets) if self.nitems >= n: offsets = np.zeros(n * N1, np.int64) offsets[:n] = self.offsets self.pos0 = align(self.fd) if np.little_endian: offsets.tofile(self.fd) else: offsets.byteswap().tofile(self.fd) writeint(self.fd, self.pos0, 40) self.offsets = offsets self.offsets[self.nitems] = i writeint(self.fd, i, self.pos0 + self.nitems * 8) self.nitems += 1 writeint(self.fd, self.nitems, 32) self.fd.flush() self.fd.seek(0, 2) # end of file self.data = {'_little_endian': np.little_endian}
def _write_metadata(self, metadata): """Write the metadata file of the bundle. Modifies the medadata dictionary! """ # Add standard fields that must always be present. assert self.state == 'write' or self.state == 'prewrite' metadata['format'] = 'BundleTrajectory' metadata['version'] = self.version metadata['subtype'] = self.subtype metadata['backend'] = self.backend_name if self.backend_name == 'ulm': metadata['ulm.singleprecision'] = self.singleprecision metadata['python_ver'] = tuple(sys.version_info) f = paropen(os.path.join(self.filename, 'metadata.json'), 'w') fido = jsonio.encode(metadata) f.write(fido) f.close() # Write a compatibility .pickle file - will be picked up by # older versions of ASE and result in a meaningful error. metadata['comment'] = ('For compatibility only - ' 'see metadata.json instead.') f = paropen(os.path.join(self.filename, 'metadata'), 'wb') pickle.dump(metadata, f, protocol=0) del metadata['comment'] f.close()
def save(self, value): json_utf8 = encode(value).encode('utf-8') try: self.fd.write(json_utf8) except Exception as ex: raise RuntimeError(f'Failed to save {value} to cache') from ex finally: self.fd.close()
def check(obj): txt = encode(obj) newobj = decode(txt, always_array=False) print(obj, '-->', newobj) assert type(obj) is type(newobj), '{} vs {}'.format( type(obj), type(newobj)) assert np.shape(obj) == np.shape(newobj) assert np.array_equal(obj, newobj)
def write(self, filename): # XXX could be provided by a class decorator, # e.g., @jsonio('bandpath'). # That decorator should also provide a static read() function. # # WIP: get rid of similar stuff in BandStructure class. from ase.parallel import paropen from ase.io.jsonio import encode with paropen(filename, 'w') as fd: fd.write(encode(self))
def _write_json(self, bigdct, ids, nextid): if world.rank > 0: return with ExitStack() as stack: if isinstance(self.filename, str): fd = stack.enter_context(open(self.filename, 'w')) else: fd = self.filename print('{', end='', file=fd) for id in ids: dct = bigdct[id] txt = ',\n '.join('"{0}": {1}'.format(key, encode(dct[key])) for key in sorted(dct.keys())) print('"{0}": {{\n {1}}},'.format(id, txt), file=fd) if self._metadata is not None: print('"metadata": {0},'.format(encode(self.metadata)), file=fd) print('"ids": {0},'.format(ids), file=fd) print('"nextid": {0}}}'.format(nextid), file=fd)
def _write_json(self, bigdct, ids, nextid): if world.rank > 0: return if isinstance(self.filename, basestring): fd = open(self.filename, 'w') else: fd = self.filename print('{', end='', file=fd) for id in ids: dct = bigdct[id] txt = ',\n '.join('"{0}": {1}'.format(key, encode(dct[key])) for key in sorted(dct.keys())) print('"{0}": {{\n {1}}},'.format(id, txt), file=fd) if self._metadata is not None: print('"metadata": {0},'.format(encode(self.metadata)), file=fd) print('"ids": {0},'.format(ids), file=fd) print('"nextid": {0}}}'.format(nextid), file=fd) if fd is not self.filename: fd.close()
def write_header(self, atoms): # Atomic numbers and periodic boundary conditions are only # written once - in the header. Store them here so that we can # check that they are the same for all images: self.numbers = atoms.get_atomic_numbers() self.pbc = atoms.get_pbc() b = self.backend b.write(version=1, pbc=self.pbc.tolist(), numbers=self.numbers) if atoms.constraints: if all(hasattr(c, 'todict') for c in atoms.constraints): b.write(constraints=encode(atoms.constraints)) if atoms.has('masses'): b.write(masses=atoms.get_masses())
def db_write_data(dbname, row_id, data): #-# import sqlite3 from ase.io.jsonio import encode, decode from ase import Atom, Atoms db = sqlite3.connect(dbname) cursor = db.cursor() # Commit changes to the database cursor.execute('UPDATE systems SET data = ? WHERE id = ?', (encode(data), row_id[0])) db.commit() db.close()
def write_header(self, atoms): # Atomic numbers and periodic boundary conditions are only # written once - in the header. Store them here so that we can # check that they are the same for all images: self.numbers = atoms.get_atomic_numbers() self.pbc = atoms.get_pbc() b = self.backend b.write(version=1, pbc=self.pbc.tolist(), numbers=self.numbers) if atoms.constraints: b.write(constraints=encode(atoms.constraints)) if atoms.has('masses'): b.write(masses=atoms.get_masses())
def _write_metadata(self, metadata): """Write the metadata file of the bundle. Modifies the medadata dictionary! """ # Add standard fields that must always be present. assert self.state == 'write' or self.state == 'prewrite' metadata['format'] = 'BundleTrajectory' metadata['version'] = self.version metadata['subtype'] = self.subtype metadata['backend'] = self.backend_name if self.backend_name == 'ulm': metadata['ulm.singleprecision'] = self.singleprecision metadata['python_ver'] = tuple(sys.version_info) fido = jsonio.encode(metadata) with paropen(self.metadata_path, 'w') as fd: fd.write(fido)
def get_traj_str(filename): from ase.db.row import AtomsRow from ase.io.jsonio import encode atoms = read_ase(filename) row = AtomsRow(atoms) dct = {} for key in row.__dict__: if key[0] == '_' or key in row._keys or key == 'id': continue dct[key] = row[key] constraints = row.get('constraints') if constraints: dct['constraints'] = constraints txt = ','.join('"{0}": {1}'.format(key, encode(dct[key])) for key in sorted(dct.keys())) atoms_txt = '{{{0}}}'.format(txt) return atoms_txt
def write_atoms(backend, atoms, write_header=True): b = backend if write_header: b.write(pbc=atoms.pbc.tolist(), numbers=atoms.numbers) if atoms.constraints: if all(hasattr(c, 'todict') for c in atoms.constraints): b.write(constraints=encode(atoms.constraints)) if atoms.has('masses'): b.write(masses=atoms.get_masses()) b.write(positions=atoms.get_positions(), cell=atoms.get_cell().tolist()) if atoms.has('tags'): b.write(tags=atoms.get_tags()) if atoms.has('momenta'): b.write(momenta=atoms.get_momenta()) if atoms.has('initial_magmoms'): b.write(magmoms=atoms.get_initial_magnetic_moments()) if atoms.has('initial_charges'): b.write(charges=atoms.get_initial_charges())
def sync(self): """Write data dictionary. Write bool, int, float, complex and str data, shapes and dtypes for ndarrays.""" self._write_header() assert self.nmissing == 0 i = self.fd.tell() s = encode(self.data).encode() writeint(self.fd, len(s)) self.fd.write(s) n = len(self.offsets) if self.nitems >= n: offsets = np.zeros(n * N1, np.int64) offsets[:n] = self.offsets self.pos0 = align(self.fd) buf = offsets if np.little_endian else offsets.byteswap() if self.hasfileno: buf.tofile(self.fd) else: self.fd.write(buf.tobytes()) writeint(self.fd, self.pos0, 40) self.offsets = offsets self.offsets[self.nitems] = i writeint(self.fd, i, self.pos0 + self.nitems * 8) self.nitems += 1 writeint(self.fd, self.nitems, 32) self.fd.flush() self.fd.seek(0, 2) # end of file if np.little_endian: self.data = {} else: self.data = {'_little_endian': False}
def write_atoms(backend, atoms, write_header=True): b = backend if write_header: b.write(pbc=atoms.pbc.tolist(), numbers=atoms.numbers) if atoms.constraints: if all(hasattr(c, 'todict') for c in atoms.constraints): b.write(constraints=encode(atoms.constraints)) if atoms.has('masses'): b.write(masses=atoms.get_masses()) b.write(positions=atoms.get_positions(), cell=atoms.get_cell().tolist()) if atoms.has('tags'): b.write(tags=atoms.get_tags()) if atoms.has('momenta'): b.write(momenta=atoms.get_momenta()) if atoms.has('magmoms'): b.write(magmoms=atoms.get_initial_magnetic_moments()) if atoms.has('charges'): b.write(charges=atoms.get_initial_charges())
def write_header(self, atoms): # Atomic numbers and periodic boundary conditions are only # written once - in the header. Store them here so that we can # check that they are the same for all images: self.numbers = atoms.get_atomic_numbers() self.pbc = atoms.get_pbc() self.celldisp = atoms.get_celldisp() b = self.backend b.write(version=1, pbc=self.pbc.tolist(), numbers=self.numbers, celldisp=self.celldisp, ) if atoms.constraints: if all(hasattr(c, 'todict') for c in atoms.constraints): b.write(constraints=encode(atoms.constraints)) if atoms.has('masses'): b.write(masses=atoms.get_masses()) tags = [] for tag in atoms.tags(): tags.append((tag.name(), str(tag.__class__).split('.')[-1], tag._arguments())) b.write(new_tags=tags)
def _make_atoms_dict(atoms): ''' Convert an ase.Atoms object into a dictionary for json storage. Arg: atoms ase.Atoms object Returns: atoms_dict A dictionary with various atoms information stored ''' # If the atoms object is relaxed, then get the magnetic moments from the # calculator. We do this because magnetic moments of individual atoms # within a structure are mutable and actually change when the atom is # pulled from the structure (even inside a list comprehension). try: magmoms = atoms.get_magnetic_moments() atoms_dict = OrderedDict( atoms=[{ 'symbol': atom.symbol, 'position': atom.position.tolist(), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': atom.momentum.tolist(), 'magmom': magmoms[i] } for i, atom in enumerate(atoms)], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # If the atoms object is unrelaxed, then get the magnetic moment from the # individual atom except RuntimeError: atoms_dict = OrderedDict( atoms=[{ 'symbol': atom.symbol, 'position': atom.position.tolist(), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': atom.momentum.tolist(), 'magmom': atom.magmom } for atom in atoms], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # Redundant information for search convenience. atoms_dict['natoms'] = len(atoms) cell = atoms.get_cell() atoms_dict['mass'] = sum(atoms.get_masses()) syms = atoms.get_chemical_symbols() atoms_dict['spacegroup'] = spglib.get_spacegroup( make_spglib_cell_from_atoms(atoms)) atoms_dict['chemical_symbols'] = list(set(syms)) atoms_dict['symbol_counts'] = {sym: syms.count(sym) for sym in syms} if cell is not None and np.linalg.det(cell) > 0: atoms_dict['volume'] = atoms.get_volume() return json.loads(encode(atoms_dict))
def write(self, filename): """Write to json file.""" with paropen(filename, 'w') as f: f.write(encode(self))
for name in all_names: check(con, name) data = {} for name in all_names: if '.' in name: symbol, e = name.split('.') params = parameters_extra[symbol] assert params['name'] == e else: symbol = name e = 'default' params = parameters[symbol] data[symbol] = [] gen = Generator(symbol, 'PBE', scalarrel=True, txt=None) gen.run(write_xml=False, **params) nlfer = [] for j in range(gen.njcore): nlfer.append((gen.n_j[j], gen.l_j[j], gen.f_j[j], gen.e_j[j], 0.0)) for n, l, f, eps in zip(gen.vn_j, gen.vl_j, gen.vf_j, gen.ve_j): nlfer.append((n, l, f, eps, gen.rcut_l[l])) energies = summary(con, name) data[symbol].append((e, nlfer, energies)) with open('datasets.json', 'w') as fd: fd.write(encode(data))
def _write(self, atoms, key_value_pairs, data): Database._write(self, atoms, key_value_pairs, data) con = self.connection or self._connect() self._initialize(con) cur = con.cursor() id = None if not isinstance(atoms, AtomsRow): row = AtomsRow(atoms) row.ctime = mtime = now() row.user = os.getenv('USER') else: row = atoms cur.execute('SELECT id FROM systems WHERE unique_id=?', (row.unique_id, )) results = cur.fetchall() if results: id = results[0][0] self._delete(cur, [id], ['keys', 'text_key_values', 'number_key_values']) mtime = now() constraints = row._constraints if constraints: if isinstance(constraints, list): constraints = encode(constraints) else: constraints = None values = (row.unique_id, row.ctime, mtime, row.user, blob(row.numbers), blob(row.positions), blob(row.cell), int(np.dot(row.pbc, [1, 2, 4])), blob(row.get('initial_magmoms')), blob(row.get('initial_charges')), blob(row.get('masses')), blob(row.get('tags')), blob(row.get('momenta')), constraints) if 'calculator' in row: values += (row.calculator, encode(row.calculator_parameters)) else: values += (None, None) if key_value_pairs is None: key_value_pairs = row.key_value_pairs if not data: data = row._data if not isinstance(data, basestring): data = encode(data) values += (row.get('energy'), row.get('free_energy'), blob(row.get('forces')), blob(row.get('stress')), blob(row.get('dipole')), blob(row.get('magmoms')), row.get('magmom'), blob(row.get('charges')), encode(key_value_pairs), data, len(row.numbers), float_if_not_none(row.get('fmax')), float_if_not_none(row.get('smax')), float(row.volume), float(row.mass), float(row.charge)) if id is None: q = self.default + ', ' + ', '.join('?' * len(values)) cur.execute('INSERT INTO systems VALUES ({0})'.format(q), values) else: q = ', '.join(line.split()[0].lstrip() + '=?' for line in init_statements[0].splitlines()[2:]) cur.execute('UPDATE systems SET {0} WHERE id=?'.format(q), values + (id, )) if id is None: id = self.get_last_id(cur) count = row.count_atoms() if count: species = [(atomic_numbers[symbol], n, id) for symbol, n in count.items()] cur.executemany('INSERT INTO species VALUES (?, ?, ?)', species) text_key_values = [] number_key_values = [] for key, value in key_value_pairs.items(): if isinstance(value, (float, int)): number_key_values.append([key, float(value), id]) else: assert isinstance(value, basestring) text_key_values.append([key, value, id]) cur.executemany('INSERT INTO text_key_values VALUES (?, ?, ?)', text_key_values) cur.executemany('INSERT INTO number_key_values VALUES (?, ?, ?)', number_key_values) cur.executemany('INSERT INTO keys VALUES (?, ?)', [(key, id) for key in key_value_pairs]) if self.connection is None: con.commit() con.close() return id
from ase.build import bulk from ase.io.jsonio import encode, decode atoms = bulk('Ti') print(atoms) #txt = encode({1:2, 3:4, 'hello': atoms}) txt = encode(atoms) print(txt) atoms1 = decode(txt) print(atoms1) txt1 = encode(atoms1) assert txt == txt1 assert atoms == atoms1
def _write_atoms(self, atoms, **kwargs): b = self.backend if self.header_data is None: b.write(version=1, ase_version=__version__) if self.description: b.write(description=self.description) # Atomic numbers and periodic boundary conditions are written # in the header in the beginning. # # If an image later on has other numbers/pbc, we write a new # header. All subsequent images will then have their own header # whether or not their numbers/pbc change. self.header_data = get_header_data(atoms) write_header = True else: if not self.multiple_headers: header_data = get_header_data(atoms) self.multiple_headers = not headers_equal( self.header_data, header_data) write_header = self.multiple_headers write_atoms(b, atoms, write_header=write_header) calc = atoms.calc if calc is None and len(kwargs) > 0: calc = SinglePointCalculator(atoms) if calc is not None: if not hasattr(calc, 'get_property'): calc = OldCalculatorWrapper(calc) c = b.child('calculator') c.write(name=calc.name) if hasattr(calc, 'todict'): c.write(parameters=calc.todict()) for prop in all_properties: if prop in kwargs: x = kwargs[prop] else: if self.properties is not None: if prop in self.properties: x = calc.get_property(prop, atoms) else: x = None else: try: x = calc.get_property(prop, atoms, allow_calculation=False) except (PropertyNotImplementedError, KeyError): # KeyError is needed for Jacapo. # XXX We can perhaps remove this. x = None if x is not None: if prop in ['stress', 'dipole']: x = x.tolist() c.write(prop, x) info = {} for key, value in atoms.info.items(): try: encode(value) except TypeError: warnings.warn('Skipping "{0}" info.'.format(key)) else: info[key] = value if info: b.write(info=info) b.sync()
def test_dict_with_int_key(): assert decode(encode({1: 2}), False)[1] == 2
def todict(self): """Convert calculator to a dictionary. This is most useful for serializing or adding to a Mongo database. This does not include the atoms object. It can fail on self.kwargs, if that contains non-serializable data, usually those are np.arrays. This should store the user, path, a list of directories in the path, the kwargs, parameters, pseudopotentials, calculated properties, and some convenience properties. Note: I use json.loads(encode(p)) from ase.io.jsonio to make sure we get serializable dictionaries here. """ from collections import OrderedDict import os # split the path by directory as a kind of set of tags. path, folder = self.directory, '' folders = [] while path != '/': if folder != '': folders.append(folder) path, folder = os.path.split(path) d = OrderedDict(name='Vasp', path=self.directory, pathtags=folders) d.update(parameters=self.parameters) d.update(potcars=self.get_pseudopotentials()) for prop in self.implemented_properties: val = self.results.get(prop, None) d[prop] = val f = self.results.get('forces', None) if f is not None: d['fmax'] = max(np.abs(f.flatten())) s = self.results.get('stress', None) if s is not None: d['smax'] = max(np.abs(s.flatten())) # NEBs remain a difficult issue. The root directory does not # have an OUTCAR so many of these don't work. Also, there is # not an obvious atoms to attach to it, or an obvious energy. # I compromise here and just store the images and energy. if not self.neb: d['elapsed-time'] = self.get_elapsed_time() d['memory-used'] = self.get_memory() d['nionic-steps'] = self.get_number_of_ionic_steps() program, version, subversion, rd, rt = self.get_program_info() d['program'] = program d['version'] = version d['subversion'] = subversion d['run-date'] = rd d['run-time'] = rt if self.neb: images, energies = self.get_neb() d['energy'] = energies from mongo import mongo_atoms_doc d['images'] = [mongo_atoms_doc(atoms) for atoms in images] return json.loads(encode(d))
def write(self, atoms=None, **kwargs): """Write the atoms to the file. If the atoms argument is not given, the atoms object specified when creating the trajectory object is used. Use keyword arguments to add extra properties:: writer.write(atoms, energy=117, dipole=[0, 0, 1.0]) """ b = self.backend if atoms is None: atoms = self.atoms if hasattr(atoms, 'interpolate'): # seems to be a NEB neb = atoms assert not neb.parallel or world.size == 1 for image in neb.images: self.write(image) return if len(b) == 0: self.write_header(atoms) else: if (atoms.pbc != self.pbc).any(): raise ValueError('Bad periodic boundary conditions!') elif len(atoms) != len(self.numbers): raise ValueError('Bad number of atoms!') elif (atoms.numbers != self.numbers).any(): raise ValueError('Bad atomic numbers!') b.write(positions=atoms.get_positions(), cell=atoms.get_cell().tolist()) if atoms.has('tags'): b.write(tags=atoms.get_tags()) if atoms.has('momenta'): b.write(momenta=atoms.get_momenta()) if atoms.has('magmoms'): b.write(magmoms=atoms.get_initial_magnetic_moments()) if atoms.has('charges'): b.write(charges=atoms.get_initial_charges()) calc = atoms.get_calculator() if calc is None and len(kwargs) > 0: calc = SinglePointCalculator(atoms) if calc is not None: if not isinstance(calc, Calculator): calc = OldCalculatorWrapper(calc) c = b.child('calculator') c.write(name=calc.name) for prop in all_properties: if prop in kwargs: x = kwargs[prop] else: if self.properties is not None: if prop in self.properties: x = calc.get_property(prop, atoms) else: x = None else: try: x = calc.get_property(prop, atoms, allow_calculation=False) except (NotImplementedError, KeyError): # KeyError is needed for Jacapo. x = None if x is not None: if prop in ['stress', 'dipole']: x = x.tolist() c.write(prop, x) info = {} for key, value in atoms.info.items(): try: encode(value) except TypeError: warnings.warn('Skipping "{0}" info.'.format(key)) else: info[key] = value if info: b.write(info=info) b.sync()
def write(self, filename): with paropen(filename, 'w') as f: f.write(encode(self))
def write(self, atoms=None, **kwargs): """Write the atoms to the file. If the atoms argument is not given, the atoms object specified when creating the trajectory object is used. Use keyword arguments to add extra properties:: writer.write(atoms, energy=117, dipole=[0, 0, 1.0]) """ b = self.backend if atoms is None: atoms = self.atoms if hasattr(atoms, 'interpolate'): # seems to be a NEB neb = atoms assert not neb.parallel or world.size == 1 for image in neb.images: self.write(image) return while hasattr(atoms, 'atoms_for_saving'): # Seems to be a Filter or similar, instructing us to # save the original atoms. atoms = atoms.atoms_for_saving if len(b) == 0: b.write(version=1, ase_version=__version__) if self.description: b.write(description=self.description) # Atomic numbers and periodic boundary conditions are only # written once - in the header. Store them here so that we can # check that they are the same for all images: self.numbers = atoms.get_atomic_numbers() self.pbc = atoms.get_pbc() else: if (atoms.pbc != self.pbc).any(): raise ValueError('Bad periodic boundary conditions!') elif len(atoms) != len(self.numbers): raise ValueError('Bad number of atoms!') elif (atoms.numbers != self.numbers).any(): raise ValueError('Bad atomic numbers!') write_atoms(b, atoms, write_header=(len(b) == 0)) calc = atoms.get_calculator() if calc is None and len(kwargs) > 0: calc = SinglePointCalculator(atoms) if calc is not None: if not hasattr(calc, 'get_property'): calc = OldCalculatorWrapper(calc) c = b.child('calculator') c.write(name=calc.name) if hasattr(calc, 'todict'): d = calc.todict() if d: c.write(parameters=d) for prop in all_properties: if prop in kwargs: x = kwargs[prop] else: if self.properties is not None: if prop in self.properties: x = calc.get_property(prop, atoms) else: x = None else: try: x = calc.get_property(prop, atoms, allow_calculation=False) except (PropertyNotImplementedError, KeyError): # KeyError is needed for Jacapo. x = None if x is not None: if prop in ['stress', 'dipole']: x = x.tolist() c.write(prop, x) info = {} for key, value in atoms.info.items(): try: encode(value) except TypeError: warnings.warn('Skipping "{0}" info.'.format(key)) else: info[key] = value if info: b.write(info=info) b.sync()
def todict(self): """Convert calculator to a dictionary. This is most useful for serializing or adding to a Mongo database. This does not include the atoms object. It can fail on self.kwargs, if that contains non-serializable data, usually those are np.arrays. This should store the user, path, a list of directories in the path, the kwargs, parameters, pseudopotentials, calculated properties, and some convenience properties. Note: I use json.loads(encode(p)) from ase.io.jsonio to make sure we get serializable dictionaries here. """ from collections import OrderedDict import os # split the path by directory as a kind of set of tags. path, folder = self.directory, '' folders = [] while path != '/': if folder != '': folders.append(folder) path, folder = os.path.split(path) d = OrderedDict(name='Vasp', path=self.directory, pathtags=folders) d.update(parameters=self.parameters) d.update(potcars=list(self.get_pseudopotentials())) for prop in self.implemented_properties: val = self.results.get(prop, None) d[prop] = val f = self.results.get('forces', None) if f is not None: d['fmax'] = max(np.abs(f.flatten())) s = self.results.get('stress', None) if s is not None: d['smax'] = max(np.abs(s.flatten())) # NEBs remain a difficult issue. The root directory does not # have an OUTCAR so many of these don't work. Also, there is # not an obvious atoms to attach to it, or an obvious energy. # I compromise here and just store the images and energy. if not self.neb: d['elapsed-time'] = self.get_elapsed_time() d['memory-used'] = self.get_memory() d['nionic-steps'] = self.get_number_of_ionic_steps() program, version, subversion, rd, rt = self.get_program_info() d['program'] = program d['version'] = version d['subversion'] = subversion d['run-date'] = rd d['run-time'] = rt #if self.neb: # images, energies = self.get_neb() # d['energy'] = energies # from .mongo import mongo_atoms_doc # d['images'] = [mongo_atoms_doc(atoms) for atoms in images] return json.loads(encode(d))
"""Test serialization of ndarrays and other stuff.""" import numpy as np from ase.io.jsonio import encode, decode assert decode(encode(np.int64(42))) == 42 c = np.array([0.1j]) assert (decode(encode(c)) == c).all()
def _write(self, atoms, key_value_pairs, data): Database._write(self, atoms, key_value_pairs, data) con = self.connection or self._connect() self._initialize(con) cur = con.cursor() id = None if not isinstance(atoms, AtomsRow): row = AtomsRow(atoms) row.ctime = mtime = now() row.user = os.getenv('USER') else: row = atoms cur.execute('SELECT id FROM systems WHERE unique_id=?', (row.unique_id,)) results = cur.fetchall() if results: id = results[0][0] self._delete(cur, [id], ['keys', 'text_key_values', 'number_key_values']) mtime = now() constraints = row._constraints if constraints: if isinstance(constraints, list): constraints = encode(constraints) else: constraints = None values = (row.unique_id, row.ctime, mtime, row.user, blob(row.numbers), blob(row.positions), blob(row.cell), int(np.dot(row.pbc, [1, 2, 4])), blob(row.get('initial_magmoms')), blob(row.get('initial_charges')), blob(row.get('masses')), blob(row.get('tags')), blob(row.get('momenta')), constraints) if 'calculator' in row: if not isinstance(row.calculator_parameters, basestring): row.calculator_parameters = encode(row.calculator_parameters) values += (row.calculator, row.calculator_parameters) else: values += (None, None) if key_value_pairs is None: key_value_pairs = row.key_value_pairs if not data: data = row._data if not isinstance(data, basestring): data = encode(data) values += (row.get('energy'), row.get('free_energy'), blob(row.get('forces')), blob(row.get('stress')), blob(row.get('dipole')), blob(row.get('magmoms')), row.get('magmom'), blob(row.get('charges')), encode(key_value_pairs), data, len(row.numbers), float_if_not_none(row.get('fmax')), float_if_not_none(row.get('smax')), float_if_not_none(row.get('volume')), float(row.mass), float(row.charge)) if id is None: q = self.default + ', ' + ', '.join('?' * len(values)) cur.execute('INSERT INTO systems VALUES ({0})'.format(q), values) else: q = ', '.join(line.split()[0].lstrip() + '=?' for line in init_statements[0].splitlines()[2:]) cur.execute('UPDATE systems SET {0} WHERE id=?'.format(q), values + (id,)) if id is None: id = self.get_last_id(cur) count = row.count_atoms() if count: species = [(atomic_numbers[symbol], n, id) for symbol, n in count.items()] cur.executemany('INSERT INTO species VALUES (?, ?, ?)', species) text_key_values = [] number_key_values = [] for key, value in key_value_pairs.items(): if isinstance(value, (float, int)): number_key_values.append([key, float(value), id]) else: assert isinstance(value, basestring) text_key_values.append([key, value, id]) cur.executemany('INSERT INTO text_key_values VALUES (?, ?, ?)', text_key_values) cur.executemany('INSERT INTO number_key_values VALUES (?, ?, ?)', number_key_values) cur.executemany('INSERT INTO keys VALUES (?, ?)', [(key, id) for key in key_value_pairs]) if self.connection is None: con.commit() con.close() return id
def write(self, atoms=None, **kwargs): """Write the atoms to the file. If the atoms argument is not given, the atoms object specified when creating the trajectory object is used. Use keyword arguments to add extra properties:: writer.write(atoms, energy=117, dipole=[0, 0, 1.0]) """ b = self.backend if atoms is None: atoms = self.atoms if hasattr(atoms, 'interpolate'): # seems to be a NEB neb = atoms assert not neb.parallel or world.size == 1 for image in neb.images: self.write(image) return while hasattr(atoms, 'atoms_for_saving'): # Seems to be a Filter or similar, instructing us to # save the original atoms. atoms = atoms.atoms_for_saving if self.header_data is None: b.write(version=1, ase_version=__version__) if self.description: b.write(description=self.description) # Atomic numbers and periodic boundary conditions are written # in the header in the beginning. # # If an image later on has other numbers/pbc, we write a new # header. All subsequent images will then have their own header # whether or not their numbers/pbc change. self.header_data = get_header_data(atoms) write_header = True else: if not self.multiple_headers: header_data = get_header_data(atoms) self.multiple_headers = not headers_equal( self.header_data, header_data) write_header = self.multiple_headers write_atoms(b, atoms, write_header=write_header) calc = atoms.get_calculator() if calc is None and len(kwargs) > 0: calc = SinglePointCalculator(atoms) if calc is not None: if not hasattr(calc, 'get_property'): calc = OldCalculatorWrapper(calc) c = b.child('calculator') c.write(name=calc.name) if hasattr(calc, 'todict'): d = calc.todict() if d: c.write(parameters=d) for prop in all_properties: if prop in kwargs: x = kwargs[prop] else: if self.properties is not None: if prop in self.properties: x = calc.get_property(prop, atoms) else: x = None else: try: x = calc.get_property(prop, atoms, allow_calculation=False) except (PropertyNotImplementedError, KeyError): # KeyError is needed for Jacapo. x = None if x is not None: if prop in ['stress', 'dipole']: x = x.tolist() c.write(prop, x) info = {} for key, value in atoms.info.items(): try: encode(value) except TypeError: warnings.warn('Skipping "{0}" info.'.format(key)) else: info[key] = value if info: b.write(info=info) b.sync()
def mongo_doc(atoms, **kwargs): """atoms is an ase.atoms.Atoms object. kwargs are key-value pairs that will be written to the database. Returns a dictionary for inserting to Mongo. The dictionary has three subdocuments: atoms calculator - generated by the calculator.todict function results - energy, forces, and stress There are couple of additional fields including the user, creation and modified time, and an inserted-hash. """ d = OrderedDict(atoms=mongo_atoms_doc(atoms)) # Calculator document calc = atoms.get_calculator() if calc is not None: if hasattr(calc, 'todict'): d['calculator'] = calc.todict() else: d['calculator'] = {} # This might make it easier to reload these later. I # believe you import the class from the module then create # an instance of the class. d['calculator']['module'] = calc.__module__ d['calculator']['class'] = calc.__class__.__name__ # Results. This may duplicate information in the calculator, # but we have no control on what the calculator does. d['results'] = OrderedDict() if atoms.get_calculator() is not None: calc = atoms.get_calculator() if not calc.calculation_required(atoms, ['energy']): d['results']['energy'] = atoms.get_potential_energy() if not calc.calculation_required(atoms, ['forces']): f = atoms.get_forces() d['results']['forces'] = f.tolist() d['results']['fmax'] = max(np.abs(f.flatten())) if not calc.calculation_required(atoms, ['stress']): s = atoms.get_stress() d['results']['stress'] = s.tolist() d['results']['smax'] = max(np.abs(s.flatten())) d['user'] = os.getenv('USER') # This is a hash of what is inserted. You might use it to # check for uniqueness of the insert. It is not clear it # belongs here since d contains results and time data. d['inserted-hash'] = hashlib.sha1(encode(d)).hexdigest() # Created time. d['ctime'] = datetime.datetime.utcnow() # Modified time - depends on user to update d['mtime'] = datetime.datetime.utcnow() d.update(kwargs) return d
import numpy as np from ase.build import bulk, molecule from ase.io.jsonio import encode, decode def assert_equal(atoms1, atoms2): assert atoms1 == atoms2 assert set(atoms1.arrays) == set(atoms2.arrays) for name in atoms1.arrays: assert np.array_equal(atoms1.arrays[name], atoms2.arrays[name]), name atoms = bulk('Ti') print('atoms', atoms) txt = encode(atoms) print('encoded', txt) atoms1 = decode(txt) print('decoded', atoms1) txt1 = encode(atoms1) assert txt == txt1 assert_equal(atoms, atoms1) BeH = molecule('BeH') assert BeH.has('initial_magmoms') new_BeH = decode(encode(BeH)) assert_equal(BeH, new_BeH) assert new_BeH.has('initial_magmoms') from ase.constraints import FixAtoms atoms = bulk('Ti')
def borncharges(calc, delta=0.01): params = calc.parameters atoms = calc.atoms cell_cv = atoms.get_cell() / Bohr vol = abs(np.linalg.det(cell_cv)) sym_a = atoms.get_chemical_symbols() Z_a = [] for num in calc.atoms.get_atomic_numbers(): for ida, setup in zip(calc.wfs.setups.id_a, calc.wfs.setups): if abs(ida[0] - num) < 1e-5: break Z_a.append(setup.Nv) Z_a = np.array(Z_a) # List for atomic indices indices = list(range(len(sym_a))) pos_av = atoms.get_positions() avg_v = np.sum(pos_av, axis=0) / len(pos_av) pos_av -= avg_v atoms.set_positions(pos_av) Z_avv = [] norm_c = np.linalg.norm(cell_cv, axis=1) proj_cv = cell_cv / norm_c[:, np.newaxis] B_cv = np.linalg.inv(cell_cv).T * 2 * np.pi area_c = np.zeros((3,), float) area_c[[2, 1, 0]] = [np.linalg.norm(np.cross(B_cv[i], B_cv[j])) for i in range(3) for j in range(3) if i < j] if world.rank == 0: print('Atomnum Atom Direction Displacement') for a in indices: phase_scv = np.zeros((2, 3, 3), float) for v in range(3): for s, sign in enumerate([-1, 1]): if world.rank == 0: print(sym_a[a], a, v, s) # Update atomic positions atoms.positions = pos_av atoms.positions[a, v] = pos_av[a, v] + sign * delta prefix = 'born-{}-{}{}{}'.format(delta, a, 'xyz'[v], ' +-'[sign]) name = prefix + '.gpw' berryname = prefix + '-berryphases.json' if not exists(name) and not exists(berryname): calc = get_wavefunctions(atoms, name, params) try: phase_c = get_polarization_phase(name) except ValueError: calc = get_wavefunctions(atoms, name, params) phase_c = get_polarization_phase(name) phase_scv[s, :, v] = phase_c if exists(berryname): # Calculation done? if world.rank == 0: # Remove gpw file if isfile(name): remove(name) dphase_cv = (phase_scv[1] - phase_scv[0]) dphase_cv -= np.round(dphase_cv / (2 * np.pi)) * 2 * np.pi dP_cv = (area_c[:, np.newaxis] / (2 * np.pi)**3 * dphase_cv) dP_vv = np.dot(proj_cv.T, dP_cv) Z_vv = dP_vv * vol / (2 * delta / Bohr) Z_avv.append(Z_vv) data = {'Z_avv': Z_avv, 'indices_a': indices, 'sym_a': sym_a} filename = 'borncharges-{}.json'.format(delta) with paropen(filename, 'w') as fd: json.dump(jsonio.encode(data), fd) world.barrier() if world.rank == 0: files = glob('born-*.gpw') for f in files: if isfile(f): remove(f)
def write(self, atoms=None, **kwargs): """Write the atoms to the file. If the atoms argument is not given, the atoms object specified when creating the trajectory object is used. Use keyword arguments to add extra properties:: writer.write(atoms, energy=117, dipole=[0, 0, 1.0]) """ b = self.backend if atoms is None: atoms = self.atoms if hasattr(atoms, 'interpolate'): # seems to be a NEB neb = atoms assert not neb.parallel or world.size == 1 for image in neb.images: self.write(image) return while hasattr(atoms, 'atoms_for_saving'): # Seems to be a Filter or similar, instructing us to # save the original atoms. atoms = atoms.atoms_for_saving if self.header_data is None: b.write(version=1, ase_version=__version__) if self.description: b.write(description=self.description) # Atomic numbers and periodic boundary conditions are written # in the header in the beginning. # # If an image later on has other numbers/pbc, we write a new # header. All subsequent images will then have their own header # whether or not their numbers/pbc change. self.header_data = get_header_data(atoms) write_header = True else: if not self.multiple_headers: header_data = get_header_data(atoms) self.multiple_headers = not headers_equal(self.header_data, header_data) write_header = self.multiple_headers write_atoms(b, atoms, write_header=write_header) calc = atoms.get_calculator() if calc is None and len(kwargs) > 0: calc = SinglePointCalculator(atoms) if calc is not None: if not hasattr(calc, 'get_property'): calc = OldCalculatorWrapper(calc) c = b.child('calculator') c.write(name=calc.name) if hasattr(calc, 'todict'): d = calc.todict() if d: c.write(parameters=d) for prop in all_properties: if prop in kwargs: x = kwargs[prop] else: if self.properties is not None: if prop in self.properties: x = calc.get_property(prop, atoms) else: x = None else: try: x = calc.get_property(prop, atoms, allow_calculation=False) except (PropertyNotImplementedError, KeyError): # KeyError is needed for Jacapo. x = None if x is not None: if prop in ['stress', 'dipole']: x = x.tolist() c.write(prop, x) info = {} for key, value in atoms.info.items(): try: encode(value) except TypeError: warnings.warn('Skipping "{0}" info.'.format(key)) else: info[key] = value if info: b.write(info=info) b.sync()