@@ -139,15 +139,18 @@ class DeepEval(DeepEvalBackend):
139139 Neighbor-list builder for the NLIST/extended lower path (``.pte`` and
140140 nlist-form ``.pt2``): ``"auto"`` / ``"vesin"`` / ``"native"``. Not
141141 used by graph-form ``.pt2`` artifacts.
142- neighbor_graph_method : str, default: "dense "
142+ neighbor_graph_method : str, default: "auto "
143143 Carry-all graph builder for GRAPH-FORM ``.pt2`` artifacts ONLY
144- (``metadata["lower_input_kind"] == "graph"``): ``"dense"`` / ``"ase"``
145- (backend-agnostic) or ``"vesin"`` / ``"nv"`` (on-device O(N)). A
146- non-default value on any other artifact raises at construction — the
147- knob would silently do nothing there; use ``nlist_backend`` for the
148- nlist path instead. All builders emit the same neighbor set, so the
149- choice is performance-only. Consolidating the two knobs into a single
150- backend-selection API is deferred to the dense-nlist deprecation.
144+ (``metadata["lower_input_kind"] == "graph"``): ``"auto"`` (availability-
145+ probed O(N) default; see
146+ :func:`~deepmd.pt_expt.utils.neighbor_graph_method.resolve_auto_graph_builder`),
147+ ``"dense"`` / ``"ase"`` (backend-agnostic), or ``"vesin"`` / ``"nv"``
148+ (on-device O(N)). A non-default explicit value on any other artifact
149+ raises at construction — the knob would silently do nothing there; use
150+ ``nlist_backend`` for the nlist path instead. All builders emit the
151+ same neighbor set, so the choice is performance-only. Consolidating
152+ the two knobs into a single backend-selection API is deferred to the
153+ dense-nlist deprecation.
151154 **kwargs : dict
152155 Keyword arguments.
153156 """
@@ -160,14 +163,14 @@ def __init__(
160163 auto_batch_size : bool | int | AutoBatchSize = True ,
161164 neighbor_list : Optional ["ase.neighborlist.NewPrimitiveNeighborList" ] = None ,
162165 nlist_backend : str = "auto" ,
163- neighbor_graph_method : str = "dense " ,
166+ neighbor_graph_method : str = "auto " ,
164167 ** kwargs : Any ,
165168 ) -> None :
166169 self .output_def = output_def
167170 self .model_path = model_file
168171 self .neighbor_list = neighbor_list
169172 # World-2 graph-form ``.pt2`` (lower_input_kind == "graph") builder select:
170- # "dense"/"ase" (backend-agnostic) or "vesin"/"nv" (on-device O(N)).
173+ # "auto" (probed) / " dense"/"ase" (backend-agnostic) / "vesin"/"nv" (O(N)).
171174 self ._neighbor_graph_method = neighbor_graph_method
172175 self ._is_pt2 = model_file .endswith (".pt2" )
173176
@@ -185,11 +188,13 @@ def __init__(
185188 )
186189
187190 # neighbor_graph_method is consumed ONLY by graph-form .pt2 eval
188- # (_eval_model_graph); fail fast instead of silently ignoring it on
189- # nlist-form artifacts (there, the builder knob is nlist_backend).
190- if neighbor_graph_method != "dense" and getattr (self , "metadata" , {}).get (
191- "lower_input_kind"
192- ) not in ("graph" , "dpa1_canonical" ):
191+ # (_eval_model_graph); fail fast instead of silently ignoring an
192+ # EXPLICIT builder on nlist-form artifacts (there, the builder knob
193+ # is nlist_backend). "auto" / "dense" are allowed as no-ops so the
194+ # default constructor works for every artifact kind.
195+ if neighbor_graph_method not in ("auto" , "dense" ) and getattr (
196+ self , "metadata" , {}
197+ ).get ("lower_input_kind" ) not in ("graph" , "dpa1_canonical" ):
193198 raise ValueError (
194199 f"neighbor_graph_method={ neighbor_graph_method !r} only applies to "
195200 "graph-form .pt2 artifacts (lower_input_kind == 'graph'); this "
@@ -1930,14 +1935,21 @@ def _build_eval_graph(
19301935 ) -> "NeighborGraph" :
19311936 """Build the carry-all NeighborGraph for graph-form ``.pt2`` inference.
19321937
1933- Dispatches on ``self._neighbor_graph_method``: ``dense``/``ase`` run
1934- backend-agnostic (numpy); ``vesin``/``nv`` run on-device (torch, O(N)).
1935- All backends emit the SAME neighbor set (carry-all, sel-free), so the
1936- selection is a pure performance choice and results are unchanged. The
1937- result is canonicalized to the destination-major graph-form ``.pt2``
1938- ABI after construction.
1938+ Dispatches on ``self._neighbor_graph_method``: ``auto`` resolves via
1939+ :func:`~deepmd.pt_expt.utils.neighbor_graph_method.resolve_auto_graph_builder`;
1940+ ``dense``/``ase`` run backend-agnostic (numpy); ``vesin``/``nv`` run
1941+ on-device (torch, O(N)). All backends emit the SAME neighbor set
1942+ (carry-all, sel-free), so the selection is a pure performance choice
1943+ and results are unchanged. The result is canonicalized to the
1944+ destination-major graph-form ``.pt2`` ABI after construction.
19391945 """
1946+ from deepmd .pt_expt .utils .neighbor_graph_method import (
1947+ resolve_auto_graph_builder ,
1948+ )
1949+
19401950 method = self ._neighbor_graph_method
1951+ if method == "auto" :
1952+ method = resolve_auto_graph_builder (device )
19411953 # Model-level ``pair_exclude_types`` is a graph-BUILD transform
19421954 # (decision #18): apply it here so the exported ``.pt2`` lower consumes a
19431955 # pre-excluded ``edge_mask`` and never re-applies it (mirrors the C++
@@ -2006,7 +2018,7 @@ def _build_eval_graph(
20062018 )
20072019 raise ValueError (
20082020 f"unknown neighbor_graph_method { method !r} ; "
2009- "use 'dense', 'ase', 'vesin', or 'nv'"
2021+ "use 'auto', ' dense', 'ase', 'vesin', or 'nv'"
20102022 )
20112023
20122024 def _model_pair_excl (self ) -> "PairExcludeMask | None" :
0 commit comments