Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build neighbor list with external Python program #3046

Merged
merged 6 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion deepmd/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class DP(Calculator):
type_dict : Dict[str, int], optional
mapping of element types and their numbers, best left None and the calculator
will infer this information from model, by default None
neighbor_list : ase.neighborlist.NeighborList, optional
The neighbor list object. If None, then build the native neighbor list.

Examples
--------
Expand Down Expand Up @@ -83,10 +85,11 @@ def __init__(
model: Union[str, "Path"],
label: str = "DP",
type_dict: Optional[Dict[str, int]] = None,
neighbor_list=None,
**kwargs,
) -> None:
Calculator.__init__(self, label=label, **kwargs)
self.dp = DeepPotential(str(Path(model).resolve()))
self.dp = DeepPotential(str(Path(model).resolve()), neighbor_list=neighbor_list)
if type_dict:
self.type_dict = type_dict
else:
Expand Down
7 changes: 7 additions & 0 deletions deepmd/infer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def DeepPotential(
load_prefix: str = "load",
default_tf_graph: bool = False,
input_map: Optional[dict] = None,
neighbor_list=None,
) -> Union[DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, DeepDOS, DeepWFC]:
"""Factory function that will inialize appropriate potential read from `model_file`.

Expand All @@ -71,6 +72,8 @@ def DeepPotential(
If uses the default tf graph, otherwise build a new tf graph for evaluation
input_map : dict, optional
The input map for tf.import_graph_def. Only work with default tf graph
neighbor_list : ase.neighborlist.NeighborList, optional
The neighbor list object. If None, then build the native neighbor list.

Returns
-------
Expand All @@ -97,6 +100,7 @@ def DeepPotential(
load_prefix=load_prefix,
default_tf_graph=default_tf_graph,
input_map=input_map,
neighbor_list=neighbor_list,
)
elif model_type == "dos":
dp = DeepDOS(
Expand All @@ -111,20 +115,23 @@ def DeepPotential(
load_prefix=load_prefix,
default_tf_graph=default_tf_graph,
input_map=input_map,
neighbor_list=neighbor_list,
)
elif model_type == "polar":
dp = DeepPolar(
mf,
load_prefix=load_prefix,
default_tf_graph=default_tf_graph,
input_map=input_map,
neighbor_list=neighbor_list,
)
elif model_type == "global_polar":
dp = DeepGlobalPolar(
mf,
load_prefix=load_prefix,
default_tf_graph=default_tf_graph,
input_map=input_map,
neighbor_list=neighbor_list,
)
elif model_type == "wfc":
dp = DeepWFC(
Expand Down
4 changes: 4 additions & 0 deletions deepmd/infer/deep_dipole.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class DeepDipole(DeepTensor):
If uses the default tf graph, otherwise build a new tf graph for evaluation
input_map : dict, optional
The input map for tf.import_graph_def. Only work with default tf graph
neighbor_list : ase.neighborlist.NeighborList, optional
The neighbor list object. If None, then build the native neighbor list.

Warnings
--------
Expand All @@ -41,6 +43,7 @@ def __init__(
load_prefix: str = "load",
default_tf_graph: bool = False,
input_map: Optional[dict] = None,
neighbor_list=None,
) -> None:
# use this in favor of dict update to move attribute from class to
# instance namespace
Expand All @@ -58,6 +61,7 @@ def __init__(
load_prefix=load_prefix,
default_tf_graph=default_tf_graph,
input_map=input_map,
neighbor_list=neighbor_list,
)

def get_dim_fparam(self) -> int:
Expand Down
95 changes: 95 additions & 0 deletions deepmd/infer/deep_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class DeepEval:
as the initial batch size.
input_map : dict, optional
The input map for tf.import_graph_def. Only work with default tf graph
neighbor_list : ase.neighborlist.NewPrimitiveNeighborList, optional
The ASE neighbor list class to produce the neighbor list. If None, the
neighbor list will be built natively in the model.
"""

load_prefix: str # set by subclass
Expand All @@ -56,6 +59,7 @@ def __init__(
default_tf_graph: bool = False,
auto_batch_size: Union[bool, int, AutoBatchSize] = False,
input_map: Optional[dict] = None,
neighbor_list=None,
):
self.graph = self._load_graph(
model_file,
Expand Down Expand Up @@ -86,6 +90,8 @@ def __init__(
else:
raise TypeError("auto_batch_size should be bool, int, or AutoBatchSize")

self.neighbor_list = neighbor_list

@property
@lru_cache(maxsize=None)
def model_type(self) -> str:
Expand Down Expand Up @@ -360,3 +366,92 @@ def eval_typeebd(self) -> np.ndarray:
t_typeebd = self._get_tensor("t_typeebd:0")
[typeebd] = run_sess(self.sess, [t_typeebd], feed_dict={})
return typeebd

def build_neighbor_list(
self,
coords: np.ndarray,
cell: Optional[np.ndarray],
atype: np.ndarray,
imap: np.ndarray,
neighbor_list,
):
"""Make the mesh with neighbor list for a single frame.

Parameters
----------
coords : np.ndarray
The coordinates of atoms. Should be of shape [natoms, 3]
cell : Optional[np.ndarray]
The cell of the system. Should be of shape [3, 3]
atype : np.ndarray
The type of atoms. Should be of shape [natoms]
imap : np.ndarray
The index map of atoms. Should be of shape [natoms]
neighbor_list : ase.neighborlist.NewPrimitiveNeighborList
ASE neighbor list. The following method or attribute will be
used/set: bothways, self_interaction, update, build, first_neigh,
pair_second, offset_vec.

Returns
-------
natoms_vec : np.ndarray
The number of atoms. This tensor has the length of Ntypes + 2
natoms[0]: nloc
natoms[1]: nall
natoms[i]: 2 <= i < Ntypes+2, number of type i atoms for nloc
coords : np.ndarray
The coordinates of atoms, including ghost atoms. Should be of
shape [nframes, nall, 3]
atype : np.ndarray
The type of atoms, including ghost atoms. Should be of shape [nall]
mesh : np.ndarray
The mesh in nei_mode=4.
imap : np.ndarray
The index map of atoms. Should be of shape [nall]
ghost_map : np.ndarray
The index map of ghost atoms. Should be of shape [nghost]
"""
pbc = np.repeat(cell is not None, 3)
cell = cell.reshape(3, 3)
positions = coords.reshape(-1, 3)
neighbor_list.bothways = True
neighbor_list.self_interaction = False
if neighbor_list.update(pbc, cell, positions):
neighbor_list.build(pbc, cell, positions)
first_neigh = neighbor_list.first_neigh.copy()
pair_second = neighbor_list.pair_second.copy()
offset_vec = neighbor_list.offset_vec.copy()
# get out-of-box neighbors
out_mask = np.any(offset_vec != 0, axis=1)
out_idx = pair_second[out_mask]
out_offset = offset_vec[out_mask]
out_coords = positions[out_idx] + out_offset.dot(cell)
atype = np.array(atype, dtype=int)
out_atype = atype[out_idx]

nloc = positions.shape[0]
nghost = out_idx.size
all_coords = np.concatenate((positions, out_coords), axis=0)
all_atype = np.concatenate((atype, out_atype), axis=0)
# convert neighbor indexes
ghost_map = pair_second[out_mask]
pair_second[out_mask] = np.arange(nloc, nloc + nghost)
# get the mesh
mesh = np.zeros(16 + nloc * 2 + pair_second.size, dtype=int)
mesh[0] = nloc
# ilist
mesh[16 : 16 + nloc] = np.arange(nloc)
# numnei
mesh[16 + nloc : 16 + nloc * 2] = first_neigh[1:] - first_neigh[:-1]
# jlist
mesh[16 + nloc * 2 :] = pair_second

# natoms_vec
natoms_vec = np.zeros(self.ntypes + 2).astype(int)
natoms_vec[0] = nloc
natoms_vec[1] = nloc + nghost
for ii in range(self.ntypes):
natoms_vec[ii + 2] = np.count_nonzero(atype == ii)
# imap append ghost atoms
imap = np.concatenate((imap, np.arange(nloc, nloc + nghost)))
return natoms_vec, all_coords, all_atype, mesh, imap, ghost_map
13 changes: 12 additions & 1 deletion deepmd/infer/deep_polar.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class DeepPolar(DeepTensor):
If uses the default tf graph, otherwise build a new tf graph for evaluation
input_map : dict, optional
The input map for tf.import_graph_def. Only work with default tf graph
neighbor_list : ase.neighborlist.NeighborList, optional
The neighbor list object. If None, then build the native neighbor list.

Warnings
--------
Expand All @@ -44,6 +46,7 @@ def __init__(
load_prefix: str = "load",
default_tf_graph: bool = False,
input_map: Optional[dict] = None,
neighbor_list=None,
) -> None:
# use this in favor of dict update to move attribute from class to
# instance namespace
Expand All @@ -61,6 +64,7 @@ def __init__(
load_prefix=load_prefix,
default_tf_graph=default_tf_graph,
input_map=input_map,
neighbor_list=neighbor_list,
)

def get_dim_fparam(self) -> int:
Expand All @@ -83,10 +87,16 @@ class DeepGlobalPolar(DeepTensor):
The prefix in the load computational graph
default_tf_graph : bool
If uses the default tf graph, otherwise build a new tf graph for evaluation
neighbor_list : ase.neighborlist.NeighborList, optional
The neighbor list object. If None, then build the native neighbor list.
"""

def __init__(
self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False
self,
model_file: str,
load_prefix: str = "load",
default_tf_graph: bool = False,
neighbor_list=None,
) -> None:
self.tensors.update(
{
Expand All @@ -101,6 +111,7 @@ def __init__(
model_file,
load_prefix=load_prefix,
default_tf_graph=default_tf_graph,
neighbor_list=None,
)

def eval(
Expand Down
Loading
Loading