From 58236f7dc82f2ce849e559621c3843ae03a7632f Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 4 Jun 2022 05:07:55 -0400 Subject: [PATCH 1/5] add data type; refactor methods * add DataType to manage types of data * refactor data checking to check type and shape of data ** fix incorrect data type in some codes * refactor methods including sub_system, append, sort_atom_types, shuffle, pick_atom_idx, and merge methods in LabeledSystem into those in System --- dpdata/bond_order_system.py | 14 +- dpdata/cp2k/output.py | 2 +- dpdata/plugins/ase.py | 2 +- dpdata/pwmat/atomconfig.py | 4 +- dpdata/pymatgen/molecule.py | 4 +- dpdata/system.py | 352 ++++++++++++++++++++---------------- dpdata/xyz/quip_gap_xyz.py | 2 +- tests/comp_sys.py | 4 + 8 files changed, 213 insertions(+), 171 deletions(-) diff --git a/dpdata/bond_order_system.py b/dpdata/bond_order_system.py index 0a43bda5f..71c2a6b20 100644 --- a/dpdata/bond_order_system.py +++ b/dpdata/bond_order_system.py @@ -1,15 +1,13 @@ #%% # Bond Order System -from dpdata.system import System, LabeledSystem, check_System, load_format +import numpy as np +from dpdata.system import System, LabeledSystem, load_format, DataType, Axis import dpdata.rdkit.utils from dpdata.rdkit.sanitize import Sanitizer, SanitizeError from copy import deepcopy from rdkit.Chem import Conformer # import dpdata.rdkit.mol2 -def check_BondOrderSystem(data): - check_System(data) - assert ('bonds' in data.keys()) class BondOrderSystem(System): ''' @@ -23,6 +21,10 @@ class BondOrderSystem(System): 1 - single bond, 2 - double bond, 3 - triple bond, 1.5 - aromatic bond - `d_example['formal_charges']` : a numpy array of size 5 x 1 ''' + DTYPES = System.DTYPES + ( + DataType("bonds", np.ndarray, (Axis.NBONDS, 3)), + DataType("formal_charges", np.ndarray, (Axis.NATOMS, 1)), + ) def __init__(self, file_name = None, fmt = 'auto', @@ -86,6 +88,7 @@ def __init__(self, if type_map: self.apply_type_map(type_map) + self.check_data() def from_fmt_obj(self, fmtobj, file_name, **kwargs): mol = fmtobj.from_bond_order_system(file_name, **kwargs) @@ -104,9 +107,6 @@ def to_fmt_obj(self, fmtobj, *args, **kwargs): self.rdkit_mol.AddConformer(conf, assignId=True) return fmtobj.to_bond_order_system(self.data, self.rdkit_mol, *args, **kwargs) - def __repr__(self): - return self.__str__() - def __str__(self): ''' A brief summary of the system diff --git a/dpdata/cp2k/output.py b/dpdata/cp2k/output.py index 808387a3b..31b29feb6 100644 --- a/dpdata/cp2k/output.py +++ b/dpdata/cp2k/output.py @@ -268,7 +268,7 @@ def handle_single_xyz_frame(self, lines): #info_dict['atom_types'] = np.asarray(atom_types_list) info_dict['coords'] = np.asarray([coords_list]).astype('float32') info_dict['energies'] = np.array([energy]).astype('float32') - info_dict['orig']=[0,0,0] + info_dict['orig'] = np.zeros(3) return info_dict #%% diff --git a/dpdata/plugins/ase.py b/dpdata/plugins/ase.py index 957aac568..5f9dff077 100644 --- a/dpdata/plugins/ase.py +++ b/dpdata/plugins/ase.py @@ -43,7 +43,7 @@ def from_system(self, atoms: "ase.Atoms", **kwargs) -> dict: 'atom_types': atom_types, 'cells': np.array([cells]).astype('float32'), 'coords': np.array([coords]).astype('float32'), - 'orig': [0,0,0], + 'orig': np.zeros(3), } return info_dict diff --git a/dpdata/pwmat/atomconfig.py b/dpdata/pwmat/atomconfig.py index 6535edc64..1b66e5ea2 100644 --- a/dpdata/pwmat/atomconfig.py +++ b/dpdata/pwmat/atomconfig.py @@ -11,7 +11,7 @@ def _to_system_data_lower(lines) : for kk in range(idx+1,idx+1+3): vector=[float(jj) for jj in lines[kk].split()[0:3]] cell.append(vector) - system['cells'] = [np.array(cell)] + system['cells'] = np.array([np.array(cell)]) coord = [] atomic_number = [] atom_numbs = [] @@ -32,7 +32,7 @@ def _to_system_data_lower(lines) : for ii in np.unique(sorted(atomic_number)) : atom_numbs.append(atomic_number.count(ii)) system['atom_numbs'] = [int(ii) for ii in atom_numbs] - system['coords'] = [np.array(coord)] + system['coords'] = np.array([np.array(coord)]) system['orig'] = np.zeros(3) atom_types = [] for idx,ii in enumerate(system['atom_numbs']) : diff --git a/dpdata/pymatgen/molecule.py b/dpdata/pymatgen/molecule.py index 06b74c168..a362bb539 100644 --- a/dpdata/pymatgen/molecule.py +++ b/dpdata/pymatgen/molecule.py @@ -24,6 +24,6 @@ def to_system_data(file_name, protect_layer = 9) : # center = [c - h_cell_size for c in mol.center_of_mass] system['orig'] = np.array([0, 0, 0]) - system['coords'] = [tmpcoord] - system['cells'] = [10.0 * np.eye(3)] + system['coords'] = np.array([tmpcoord]) + system['cells'] = np.array([10.0 * np.eye(3)]) return system diff --git a/dpdata/system.py b/dpdata/system.py index df305a6e0..85381dfcf 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -1,11 +1,13 @@ #%% +from hashlib import new import os import glob import inspect import numpy as np import dpdata.md.pbc from copy import deepcopy -from typing import Any +from enum import Enum, unique +from typing import Any, Tuple from monty.json import MSONable from monty.serialization import loadfn,dumpfn from dpdata.periodic_table import Element @@ -35,6 +37,99 @@ def load_format(fmt): fmt, " ".join(formats) )) +@unique +class Axis(Enum): + """Data axis.""" + NFRAMES = "nframes" + NATOMS = "natoms" + NTYPES = "ntypes" + NBONDS = "nbonds" + + +class DataError(Exception): + """Data is not correct.""" + + +class DataType: + """DataType represents a type of data, like coordinates, energies, etc. + + Parameters + ---------- + name : str + name of data + dtype : type or tuple[type] + data type, e.g. np.ndarray + shape : tuple[int], optional + shape of data. Used when data is list or np.ndarray. Use Axis to + represents numbers + required : bool, default=True + whether this data is required + """ + def __init__(self, name: str, dtype: type, shape: Tuple[int, Axis]=None, required: bool=True) -> None: + self.name = name + self.dtype = dtype + self.shape = shape + self.required = required + + def real_shape(self, system: "System") -> Tuple[int]: + """Returns expected real shape of a system.""" + shape = [] + for ii in self.shape: + if ii is Axis.NFRAMES: + shape.append(system.get_nframes()) + elif ii is Axis.NTYPES: + shape.append(system.get_ntypes()) + elif ii is Axis.NATOMS: + shape.append(system.get_natoms()) + elif ii is Axis.NBONDS: + # BondOrderSystem + shape.append(system.get_nbonds()) + elif isinstance(ii, int): + shape.append(ii) + else: + raise RuntimeError("Shape is not an int!") + return tuple(shape) + + def check(self, system: "System"): + """Check if a system has correct data of this type. + + Parameters + ---------- + system : System + checked system + + Raises + ------ + DataError + type or shape of data is not correct + """ + # check if exists + if self.name in system.data: + data = system.data[self.name] + # check dtype + # allow list for empty np.ndarray + if isinstance(data, list) and not len(data): + pass + elif not isinstance(data, self.dtype): + raise DataError("Type of %s is %s, but expected %s" % (self.name, + type(data).__name__, self.dtype.__name__)) + # check shape + if self.shape is not None: + shape = self.real_shape(system) + # skip checking empty list of np.ndarray + if isinstance(data, np.ndarray): + if data.size and shape != data.shape: + raise DataError("Shape of %s is %s, but expected %s" % (self.name, + data.shape, shape)) + elif isinstance(data, list): + if len(shape) and shape[0] != len(data): + raise DataError("Length of %s is %d, but expected %d" % (self.name, + len(shape), shape[0])) + else: + raise RuntimeError("Unsupported type to check shape") + elif self.required: + raise DataError("%s not found in data" % self.name) + class System (MSONable) : ''' @@ -59,7 +154,21 @@ class System (MSONable) : Restrictions: - `d_example['orig']` is always [0, 0, 0] - `d_example['cells'][ii]` is always lower triangular (lammps cell tensor convention) + + Attributes + ---------- + DTYPES : tuple[DataType] + data types of this class ''' + DTYPES = ( + DataType("atom_numbs", list, (Axis.NTYPES,)), + DataType("atom_names", list, (Axis.NTYPES,)), + DataType("atom_types", np.ndarray, (Axis.NATOMS,)), + DataType("orig", np.ndarray, (3,)), + DataType("cells", np.ndarray, (Axis.NFRAMES, 3, 3)), + DataType("coords", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), + DataType("nopbc", bool, required=False), + ) def __init__ (self, file_name = None, @@ -110,8 +219,8 @@ def __init__ (self, self.data['coords'] = [] if data: - check_System(data) self.data=data + self.check_data() return if file_name is None : return @@ -120,6 +229,21 @@ def __init__ (self, if type_map is not None: self.apply_type_map(type_map) + def check_data(self): + """Check if data is correct. + + Raises + ------ + DataError + if data is not correct + """ + if not isinstance(self.data, dict): + raise DataError("data is not a dict!") + for dd in self.DTYPES: + dd.check(self) + if sum(self.get_atom_numbs()) != self.get_natoms(): + raise DataError("Sum of atom_numbs (%d) is not equal to natoms (%d)." % (sum(self.get_atom_numbs()), self.get_natoms())) + post_funcs = Plugin() def from_fmt(self, file_name, fmt='auto', **kwargs): @@ -136,6 +260,7 @@ def from_fmt_obj(self, fmtobj, file_name, **kwargs): self.append(System(data=dd)) else: self.data = {**self.data, **data} + self.check_data() if hasattr(fmtobj.from_system, 'post_func'): for post_f in fmtobj.from_system.post_func: self.post_funcs.get_plugin(post_f)(self) @@ -283,6 +408,9 @@ def get_natoms(self) : """Returns total number of atoms in the system""" return len(self.data['atom_types']) + def get_ntypes(self) -> int: + """Returns total number of atom types in the system.""" + return len(self.data['atom_names']) def copy(self): """Returns a copy of the system. """ @@ -304,13 +432,21 @@ def sub_system(self, f_idx) : The subsystem """ 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['coords'] = self.data['coords'][f_idx].reshape(-1, self.data['coords'].shape[1], 3) - tmp.data['nopbc'] = self.nopbc - + # convert int to array_like + if isinstance(f_idx, (int, np.int64)): + f_idx = np.array([f_idx]) + for tt in self.DTYPES: + if tt.name not in self.data: + # skip optional data + continue + if tt.shape is not None and Axis.NFRAMES in tt.shape: + axis_nframes = tt.shape.index(Axis.NFRAMES) + new_shape = [slice(None) for _ in self.data[tt.name].shape] + new_shape[axis_nframes] = f_idx + tmp.data[tt.name] = self.data[tt.name][tuple(new_shape)] + else: + # keep the original data + tmp.data[tt.name] = self.data[tt.name] return tmp @@ -345,8 +481,19 @@ def append(self, system) : for ii in ['atom_types','orig'] : eq = [v1==v2 for v1,v2 in zip(system.data[ii], self.data[ii])] assert(all(eq)) - for ii in ['coords', 'cells'] : - self.data[ii] = np.concatenate((self.data[ii], system[ii]), axis = 0) + for tt in self.DTYPES: + # check if the first shape is nframes + if tt.shape is not None and Axis.NFRAMES in tt.shape: + if tt.name not in self.data and tt.name in system.data: + raise RuntimeError('system has %s, but this does not' % tt.name) + elif tt.name in self.data and tt.name not in system.data: + raise RuntimeError('this has %s, but system does not' % tt.name) + elif tt.name not in self.data and tt.name not in system.data: + # skip if both not exist + continue + # concat any data in nframes axis + axis_nframes = tt.shape.index(Axis.NFRAMES) + self.data[tt.name] = np.concatenate((self.data[tt.name], system[tt.name]), axis=axis_nframes) if self.nopbc and not system.nopbc: # appended system uses PBC, cancel nopbc self.data['nopbc'] = False @@ -384,10 +531,24 @@ def apply_type_map(self, type_map) : else: raise RuntimeError('invalid type map, cannot be applied') - def sort_atom_types(self): + def sort_atom_types(self) -> np.ndarray: + """Sort atom types. + + Returns + ------- + idx : np.ndarray + new atom index in the Axis.NATOMS + """ idx = np.argsort(self.data['atom_types']) - self.data['atom_types'] = self.data['atom_types'][idx] - self.data['coords'] = self.data['coords'][:, idx] + for tt in self.DTYPES: + if tt.name not in self.data: + # skip optional data + continue + if tt.shape is not None and Axis.NATOMS in tt.shape: + axis_natoms = tt.shape.index(Axis.NATOMS) + new_shape = [slice(None) for _ in self.data[tt.name].shape] + new_shape[axis_natoms] = idx + self.data[tt.name] = self.data[tt.name][tuple(new_shape)] return idx @property @@ -639,8 +800,7 @@ def nopbc(self, value): def shuffle(self): """Shuffle frames randomly.""" idx = np.random.permutation(self.get_nframes()) - for ii in ['cells', 'coords']: - self.data[ii] = self.data[ii][idx] + self.data = self.sub_system(idx).data return idx def predict(self, *args: Any, driver: str="dp", **kwargs: Any) -> "LabeledSystem": @@ -687,8 +847,17 @@ def pick_atom_idx(self, idx, nopbc=None): new system """ new_sys = self.copy() - new_sys.data['coords'] = self.data['coords'][:, idx, :] - new_sys.data['atom_types'] = self.data['atom_types'][idx] + if isinstance(idx, (int, np.int64)): + idx = np.array([idx]) + for tt in self.DTYPES: + if tt.name not in self.data: + # skip optional data + continue + if tt.shape is not None and Axis.NATOMS in tt.shape: + axis_natoms = tt.shape.index(Axis.NATOMS) + new_shape = [slice(None) for _ in self.data[tt.name].shape] + new_shape[axis_natoms] = idx + new_sys.data[tt.name] = self.data[tt.name][tuple(new_shape)] # recalculate atom_numbs according to atom_types atom_numbs = np.bincount(new_sys.data['atom_types'], minlength=len(self.get_atom_names())) new_sys.data['atom_numbs'] = list(atom_numbs) @@ -799,18 +968,6 @@ class LabeledSystem (System): It is noted that - The order of frames stored in `'energies'`, `'forces'` and `'virials'` should be consistent with `'atom_types'`, `'cells'` and `'coords'`. - The order of atoms in **every** frame of `'forces'` should be consistent with `'coords'` and `'atom_types'`. - ''' - - def __init__ (self, - file_name = None, - fmt = 'auto', - type_map = None, - begin = 0, - step = 1, - data=None, - **kwargs) : - """ - Constructor Parameters ---------- @@ -841,19 +998,14 @@ def __init__ (self, The beginning frame when loading MD trajectory. step : int The number of skipped frames when loading MD trajectory. - """ - - System.__init__(self) + ''' - if data: - check_LabeledSystem(data) - self.data=data - return - if file_name is None : - return - self.from_fmt(file_name, fmt, type_map=type_map, begin= begin, step=step, **kwargs) - if type_map is not None: - self.apply_type_map(type_map) + DTYPES = System.DTYPES + ( + DataType("energies", np.ndarray, (Axis.NFRAMES,)), + DataType("forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), + DataType("virials", np.ndarray, (Axis.NFRAMES, 3, 3), required=False), + DataType("atom_pref", np.ndarray, (Axis.NFRAMES, Axis.NATOMS), required=False), + ) post_funcs = Plugin() + System.post_funcs @@ -865,6 +1017,7 @@ def from_fmt_obj(self, fmtobj, file_name, **kwargs): self.append(LabeledSystem(data=dd)) else: self.data = {**self.data, **data} + self.check_data() if hasattr(fmtobj.from_labeled_system, 'post_func'): for post_f in fmtobj.from_labeled_system.post_func: self.post_funcs.get_plugin(post_f)(self) @@ -873,9 +1026,6 @@ def from_fmt_obj(self, fmtobj, file_name, **kwargs): def to_fmt_obj(self, fmtobj, *args, **kwargs): return fmtobj.to_labeled_system(self.data, *args, **kwargs) - def __repr__(self): - return self.__str__() - def __str__(self): ret="Data Summary" ret+="\nLabeled System" @@ -925,68 +1075,6 @@ def rot_frame_lower_triangular(self, f_idx = 0) : self.affine_map_fv(trans, f_idx = f_idx) return trans - def sub_system(self, f_idx) : - """ - Construct a subsystem from the system - - Parameters - ---------- - f_idx : int or index - Which frame to use in the subsystem - - Returns - ------- - sub_system : LabeledSystem - The subsystem - """ - tmp_sys = LabeledSystem() - tmp_sys.data = System.sub_system(self, f_idx).data - tmp_sys.data['energies'] = np.atleast_1d(self.data['energies'][f_idx]) - tmp_sys.data['forces'] = self.data['forces'][f_idx].reshape(-1, self.data['forces'].shape[1], 3) - if 'virials' in self.data: - tmp_sys.data['virials'] = self.data['virials'][f_idx].reshape(-1, 3, 3) - return tmp_sys - - def append(self, system): - """ - Append a system to this system - - Parameters - ---------- - system : System - The system to append - """ - if not System.append(self, system): - # skip if this system or the system to append is non-converged - return - tgt = ['energies', 'forces'] - for ii in ['atom_pref']: - if ii in self.data: - tgt.append(ii) - if ('virials' in system.data) and ('virials' not in self.data): - raise RuntimeError('system has virial, but this does not') - if ('virials' not in system.data) and ('virials' in self.data): - raise RuntimeError('this has virial, but system does not') - if 'virials' in system.data : - tgt.append('virials') - for ii in tgt: - self.data[ii] = np.concatenate((self.data[ii], system[ii]), axis = 0) - - def sort_atom_types(self): - idx = System.sort_atom_types(self) - self.data['forces'] = self.data['forces'][:, idx] - for ii in ['atom_pref']: - if ii in self.data: - self.data[ii] = self.data[ii][:, idx] - - def shuffle(self): - """Also shuffle labeled data e.g. energies and forces.""" - idx = System.shuffle(self) - for ii in ['energies', 'forces', 'virials', 'atom_pref']: - if ii in self.data: - self.data[ii] = self.data[ii][idx] - return idx - def correction(self, hl_sys): """Get energy and force correction between self and a high-level LabeledSystem. The self's coordinates will be kept, but energy and forces will be replaced by @@ -1014,26 +1102,6 @@ def correction(self, hl_sys): corrected_sys.data['virials'] = hl_sys.data['virials'] - self.data['virials'] return corrected_sys - def pick_atom_idx(self, idx, nopbc=None): - """Pick atom index - - Parameters - ---------- - idx: int or list or slice - atom index - nopbc: Boolen (default: None) - If nopbc is True or False, set nopbc - - Returns - ------- - new_sys: LabeledSystem - new system - """ - new_sys = System.pick_atom_idx(self, idx, nopbc=nopbc) - # forces - new_sys.data['forces'] = self.data['forces'][:, idx, :] - return new_sys - class MultiSystems: '''A set containing several systems.''' @@ -1282,33 +1350,3 @@ def to_format(self, *args, **kwargs): setattr(MultiSystems, method, get_func(formatcls)) add_format_methods() - -def check_System(data): - keys={'atom_names','atom_numbs','cells','coords','orig','atom_types'} - assert( isinstance(data,dict) ) - assert( keys.issubset(set(data.keys())) ) - if len(data['coords']) > 0 : - assert( len(data['coords'][0])==len(data['atom_types'])==sum(data['atom_numbs']) ) - else : - assert( len(data['atom_types'])==sum(data['atom_numbs']) ) - assert( len(data['cells']) == len(data['coords']) ) - assert( len(data['atom_names'])==len(data['atom_numbs']) ) - -def check_LabeledSystem(data): - keys={'atom_names', 'atom_numbs', 'atom_types', 'cells', 'coords', 'energies', - 'forces', 'orig'} - - assert( keys.issubset(set(data.keys())) ) - assert( isinstance(data,dict) ) - assert( len(data['atom_names'])==len(data['atom_numbs']) ) - - if len(data['coords']) > 0 : - assert( len(data['coords'][0])==len(data['atom_types']) ==sum(data['atom_numbs']) ) - else: - assert( len(data['atom_types']) ==sum(data['atom_numbs']) ) - if 'virials' in data: - assert( len(data['cells']) == len(data['coords']) == len(data['virials']) == len(data['energies']) ) - else: - assert( len(data['cells']) == len(data['coords']) == len(data['energies']) ) - - diff --git a/dpdata/xyz/quip_gap_xyz.py b/dpdata/xyz/quip_gap_xyz.py index 54e74376d..e902958ac 100644 --- a/dpdata/xyz/quip_gap_xyz.py +++ b/dpdata/xyz/quip_gap_xyz.py @@ -129,5 +129,5 @@ def handle_single_xyz_frame(lines): info_dict['forces'] = np.array([force_array]).astype('float32') if virials is not None: info_dict['virials'] = virials - info_dict['orig'] = [0,0,0] + info_dict['orig'] = np.zeros(3) return info_dict diff --git a/tests/comp_sys.py b/tests/comp_sys.py index 3996b0f42..94c3e52a0 100644 --- a/tests/comp_sys.py +++ b/tests/comp_sys.py @@ -54,6 +54,10 @@ def test_coord(self): def test_nopbc(self): self.assertEqual(self.system_1.nopbc, self.system_2.nopbc) + def test_data_check(self): + self.system_1.check_data() + self.system_2.check_data() + class CompLabeledSys (CompSys) : def test_energy(self) : From 890655d6ee74202d141a4fb96e6217fd4e10a112 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 4 Jun 2022 05:09:43 -0400 Subject: [PATCH 2/5] small fix --- dpdata/pwmat/atomconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dpdata/pwmat/atomconfig.py b/dpdata/pwmat/atomconfig.py index 1b66e5ea2..bc06f3470 100644 --- a/dpdata/pwmat/atomconfig.py +++ b/dpdata/pwmat/atomconfig.py @@ -11,7 +11,7 @@ def _to_system_data_lower(lines) : for kk in range(idx+1,idx+1+3): vector=[float(jj) for jj in lines[kk].split()[0:3]] cell.append(vector) - system['cells'] = np.array([np.array(cell)]) + system['cells'] = np.array([cell]) coord = [] atomic_number = [] atom_numbs = [] @@ -32,7 +32,7 @@ def _to_system_data_lower(lines) : for ii in np.unique(sorted(atomic_number)) : atom_numbs.append(atomic_number.count(ii)) system['atom_numbs'] = [int(ii) for ii in atom_numbs] - system['coords'] = np.array([np.array(coord)]) + system['coords'] = np.array([coord]) system['orig'] = np.zeros(3) atom_types = [] for idx,ii in enumerate(system['atom_numbs']) : From 5a61cb36cf12248372356704e87ee1252077eda5 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 4 Jun 2022 05:16:10 -0400 Subject: [PATCH 3/5] fix the shape of formal_charges. Looks like the docstring is wrong --- dpdata/bond_order_system.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpdata/bond_order_system.py b/dpdata/bond_order_system.py index 71c2a6b20..f2a66fd2a 100644 --- a/dpdata/bond_order_system.py +++ b/dpdata/bond_order_system.py @@ -23,8 +23,9 @@ class BondOrderSystem(System): ''' DTYPES = System.DTYPES + ( DataType("bonds", np.ndarray, (Axis.NBONDS, 3)), - DataType("formal_charges", np.ndarray, (Axis.NATOMS, 1)), + DataType("formal_charges", np.ndarray, (Axis.NATOMS,)), ) + def __init__(self, file_name = None, fmt = 'auto', From 6b15e2aa59a6993141b64716c87c5dcfdcb8c490 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 4 Jun 2022 14:57:41 -0400 Subject: [PATCH 4/5] remove wrong import --- dpdata/system.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dpdata/system.py b/dpdata/system.py index 85381dfcf..69382c09e 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -1,5 +1,4 @@ #%% -from hashlib import new import os import glob import inspect From 56470af5915b2f45ae9dc34f2cd3bdc7d46e8b22 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 4 Jun 2022 16:53:33 -0400 Subject: [PATCH 5/5] fix system class in sub_system --- dpdata/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpdata/system.py b/dpdata/system.py index 69382c09e..12f839e86 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -430,7 +430,7 @@ def sub_system(self, f_idx) : sub_system : System The subsystem """ - tmp = System() + tmp = self.__class__() # convert int to array_like if isinstance(f_idx, (int, np.int64)): f_idx = np.array([f_idx])