From 8380aa78d2cf69a6f9da9c0c49781921b5dd8f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 1 Dec 2020 12:19:15 +0100 Subject: [PATCH 1/6] export energy, forces and virials to se atoms --- dpdata/system.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dpdata/system.py b/dpdata/system.py index bba7446f0..2de9b1e18 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -309,9 +309,14 @@ def sub_system(self, f_idx) : tmp = System() for ii in ['atom_numbs', 'atom_names', 'atom_types', 'orig'] : tmp.data[ii] = self.data[ii] + tmp.data['cells'] = self.data['cells'][f_idx].reshape(-1, 3, 3) + tmp.data['virials'] = self.data['virials'][f_idx].reshape(-1, 3, 3) tmp.data['coords'] = self.data['coords'][f_idx].reshape(-1, self.data['coords'].shape[1], 3) + tmp.data['forces'] = self.data['forces'][f_idx].reshape(-1, self.data['forces'].shape[1], 3) + tmp.data['energies'] = self.data['energies'][f_idx] tmp.data['nopbc'] = self.nopbc + return tmp @@ -519,12 +524,20 @@ def to_ase_structure(self): structures=[] try: from ase import Atoms - except: - raise ImportError('No module ase.Atoms') + from ase.calculators.singlepoint import SinglePointCalculator + except ImportError: + raise ImportError('No module ase') for system in self.to_list(): species=[system.data['atom_names'][tt] for tt in system.data['atom_types']] structure=Atoms(symbols=species,positions=system.data['coords'][0],pbc=True,cell=system.data['cells'][0]) + calc = SinglePointCalculator( + structure, + energy=system.data["energies"][0], + forces=system.data['forces'][0], + stresses=system.data['virials'][0] + ) + structure.calc = calc structures.append(structure) return structures From c487f05223a24f2ade8e36b47c89d6cda287c32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 1 Dec 2020 12:21:41 +0100 Subject: [PATCH 2/6] remove try-except block for import it is not necessary --- dpdata/system.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dpdata/system.py b/dpdata/system.py index 2de9b1e18..df83f7f94 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -521,12 +521,10 @@ def to_ase_structure(self): convert System to ASE Atom obj ''' + from ase import Atoms + from ase.calculators.singlepoint import SinglePointCalculator + structures=[] - try: - from ase import Atoms - from ase.calculators.singlepoint import SinglePointCalculator - except ImportError: - raise ImportError('No module ase') for system in self.to_list(): species=[system.data['atom_names'][tt] for tt in system.data['atom_types']] From 0901cfde96809f45e962bfb7ab39042ed243501c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 1 Dec 2020 12:46:36 +0100 Subject: [PATCH 3/6] convert ASE stress tensot to GPa --- dpdata/system.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dpdata/system.py b/dpdata/system.py index df83f7f94..1b8407876 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -529,11 +529,14 @@ def to_ase_structure(self): for system in self.to_list(): species=[system.data['atom_names'][tt] for tt in system.data['atom_types']] structure=Atoms(symbols=species,positions=system.data['coords'][0],pbc=True,cell=system.data['cells'][0]) + # convert to GPa as this is ase convention + v_pref = 1 * 1e4 / 1.602176621e6 + vol = structure.get_volume() calc = SinglePointCalculator( structure, energy=system.data["energies"][0], forces=system.data['forces'][0], - stresses=system.data['virials'][0] + stresses=system.data['virials'][0] / (v_pref * vol) ) structure.calc = calc structures.append(structure) From 931c606d8eefbff75f7377cde828c1d084952933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 1 Dec 2020 14:23:41 +0100 Subject: [PATCH 4/6] account for energies, forces or virials not present --- dpdata/system.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/dpdata/system.py b/dpdata/system.py index 1b8407876..8091ad32d 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -311,11 +311,15 @@ def sub_system(self, f_idx) : tmp.data[ii] = self.data[ii] tmp.data['cells'] = self.data['cells'][f_idx].reshape(-1, 3, 3) - tmp.data['virials'] = self.data['virials'][f_idx].reshape(-1, 3, 3) tmp.data['coords'] = self.data['coords'][f_idx].reshape(-1, self.data['coords'].shape[1], 3) - tmp.data['forces'] = self.data['forces'][f_idx].reshape(-1, self.data['forces'].shape[1], 3) - tmp.data['energies'] = self.data['energies'][f_idx] tmp.data['nopbc'] = self.nopbc + + if 'forces' in self.data: + tmp.data['forces'] = self.data['forces'][f_idx].reshape(-1, self.data['forces'].shape[1], 3) + if 'virials' in self.data: + tmp.data['virials'] = self.data['virials'][f_idx].reshape(-1, 3, 3) + if 'energies' in self.data: + tmp.data['energies'] = self.data['energies'][f_idx] return tmp @@ -532,14 +536,19 @@ def to_ase_structure(self): # convert to GPa as this is ase convention v_pref = 1 * 1e4 / 1.602176621e6 vol = structure.get_volume() - calc = SinglePointCalculator( - structure, - energy=system.data["energies"][0], - forces=system.data['forces'][0], - stresses=system.data['virials'][0] / (v_pref * vol) - ) + + results = {} + if "energies" in system.data: + results['energy'] = system.data["energies"][0] + if "forces" in system.data: + results['forces'] = system.data["forces"][0] + if "virials" in system.data: + results['stress'] = system.data["virials"][0] / (v_pref * vol) + + calc = SinglePointCalculator(structure, **results) structure.calc = calc structures.append(structure) + return structures @register_to_funcs.register_funcs("lammps/lmp") From 4288f5209a3e2e3f47724e8959607cf40c686f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 2 Dec 2020 11:01:25 +0100 Subject: [PATCH 5/6] reimplement to_ase_structure in labeled system --- dpdata/system.py | 53 ++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/dpdata/system.py b/dpdata/system.py index 8091ad32d..d3542e52e 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -313,13 +313,6 @@ def sub_system(self, f_idx) : tmp.data['cells'] = self.data['cells'][f_idx].reshape(-1, 3, 3) tmp.data['coords'] = self.data['coords'][f_idx].reshape(-1, self.data['coords'].shape[1], 3) tmp.data['nopbc'] = self.nopbc - - if 'forces' in self.data: - tmp.data['forces'] = self.data['forces'][f_idx].reshape(-1, self.data['forces'].shape[1], 3) - if 'virials' in self.data: - tmp.data['virials'] = self.data['virials'][f_idx].reshape(-1, 3, 3) - if 'energies' in self.data: - tmp.data['energies'] = self.data['energies'][f_idx] return tmp @@ -526,27 +519,12 @@ def to_ase_structure(self): ''' from ase import Atoms - from ase.calculators.singlepoint import SinglePointCalculator structures=[] for system in self.to_list(): species=[system.data['atom_names'][tt] for tt in system.data['atom_types']] structure=Atoms(symbols=species,positions=system.data['coords'][0],pbc=True,cell=system.data['cells'][0]) - # convert to GPa as this is ase convention - v_pref = 1 * 1e4 / 1.602176621e6 - vol = structure.get_volume() - - results = {} - if "energies" in system.data: - results['energy'] = system.data["energies"][0] - if "forces" in system.data: - results['forces'] = system.data["forces"][0] - if "virials" in system.data: - results['stress'] = system.data["virials"][0] / (v_pref * vol) - - calc = SinglePointCalculator(structure, **results) - structure.calc = calc structures.append(structure) return structures @@ -1361,6 +1339,37 @@ def sub_system(self, f_idx) : tmp_sys.data['virials'] = self.data['virials'][f_idx].reshape(-1, 3, 3) return tmp_sys + @register_to_funcs.register_funcs("ase/structure") + def to_ase_structure(self): + '''Convert System to ASE Atoms object.''' + from ase import Atoms + from ase.calculators.singlepoint import SinglePointCalculator + + structures = [] + + for system in self.to_list(): + species=[system.data['atom_names'][tt] for tt in system.data['atom_types']] + structure=Atoms( + symbols=species, + positions=system.data['coords'][0], + pbc=True, + cell=system.data['cells'][0] + ) + + results = { + 'energy': system.data["energies"][0], + 'forces': system.data["forces"][0] + } + if "virials" in system.data: + # convert to GPa as this is ase convention + v_pref = 1 * 1e4 / 1.602176621e6 + vol = structure.get_volume() + results['stress'] = system.data["virials"][0] / (v_pref * vol) + + structure.calc = SinglePointCalculator(structure, **results) + structures.append(structure) + + return structures def append(self, system): """ From 79bc35b08ac8b83238b139c6d2208a8e00c553cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 2 Dec 2020 14:04:37 +0100 Subject: [PATCH 6/6] bugfix - register to_ase_structure correctly --- dpdata/system.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dpdata/system.py b/dpdata/system.py index d3542e52e..f5e1ffb3e 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -40,6 +40,10 @@ def decorator(func): return func return decorator + def __add__(self, other): + self.funcs.update(other.funcs) + return self + class System (MSONable) : ''' @@ -1046,6 +1050,7 @@ def __init__ (self, self.apply_type_map(type_map) register_from_funcs = Register() + register_to_funcs = System.register_to_funcs + Register() def __repr__(self): return self.__str__()