@@ -32,30 +32,31 @@ class TestCollectiveVariable(torch.nn.Module):
3232 CV^2 are returned.
3333 """
3434
35- def __init__ (self , cutoff , multiple_properties ):
35+ def __init__ (self , cutoff , multiple_properties , feature_key = "feature" ):
3636 super ().__init__ ()
3737
3838 self ._nl_request = NeighborListOptions (
3939 cutoff = cutoff , full_list = True , strict = True
4040 )
4141 self ._multiple_properties = multiple_properties
42+ self ._feature_key = feature_key
4243
4344 def forward (
4445 self ,
4546 systems : List [System ],
4647 outputs : Dict [str , ModelOutput ],
4748 selected_atoms : Optional [Labels ],
4849 ) -> Dict [str , TensorMap ]:
49- if "features" not in outputs :
50+ if self . _feature_key not in outputs :
5051 return {}
5152
5253 device = torch .device ("cpu" )
5354 if len (systems ) > 0 :
5455 device = systems [0 ].positions .device
5556
56- output = outputs ["features" ]
57+ output = outputs [self . _feature_key ]
5758
58- if output .per_atom :
59+ if output .sample_kind == "atom" :
5960 samples_list : List [List [int ]] = []
6061 for s , system in enumerate (systems ):
6162 for i in range (len (system )):
@@ -67,6 +68,7 @@ def forward(
6768 sample_values .reshape (- 1 , 2 ),
6869 )
6970 else :
71+ assert output .sample_kind == "system"
7072 samples = Labels (
7173 "system" , torch .arange (len (systems ), device = device ).reshape (- 1 , 1 )
7274 )
@@ -89,14 +91,14 @@ def forward(
8991 distances = torch .linalg .vector_norm (neighbors .values .reshape (- 1 , 3 ), dim = 1 )
9092 inv_dist = 1.0 / distances
9193
92- if output .per_atom :
94+ if output .sample_kind == "atom" :
9395 sliced = values [system_start :system_stop , 0 ]
9496 sliced += sliced .index_add (0 , atom_index , inv_dist )
9597 else :
9698 values [system_i , 0 ] += inv_dist .sum ()
9799
98100 if self ._multiple_properties :
99- if output .per_atom :
101+ if output .sample_kind == "atom" :
100102 sliced = values [system_start :system_stop , 1 ]
101103 sliced += sliced .index_add (0 , atom_index , inv_dist ** 2 )
102104 else :
@@ -116,14 +118,14 @@ def forward(
116118 )
117119
118120 if selected_atoms is not None :
119- if output .per_atom :
121+ if output .sample_kind == "atom" :
120122 cv = mts .slice (cv , axis = "samples" , selection = selected_atoms )
121123 else :
122124 raise ValueError (
123125 "selected atoms is only supported with per-atom output"
124126 )
125127
126- return {"features" : cv }
128+ return {self . _feature_key : cv }
127129
128130 def requested_neighbor_lists (self ) -> List [NeighborListOptions ]:
129131 return [self ._nl_request ]
@@ -132,7 +134,7 @@ def requested_neighbor_lists(self) -> List[NeighborListOptions]:
132134CUTOFF = 3.5
133135
134136capabilities = ModelCapabilities (
135- outputs = {"features " : ModelOutput (per_atom = True )},
137+ outputs = {"feature " : ModelOutput (sample_kind = "atom" )},
136138 interaction_range = CUTOFF ,
137139 supported_devices = ["cpu" , "mps" , "cuda" ],
138140 length_unit = "A" ,
@@ -152,7 +154,7 @@ def requested_neighbor_lists(self) -> List[NeighborListOptions]:
152154model .save ("vector-per-atom.pt" )
153155
154156capabilities = ModelCapabilities (
155- outputs = {"features " : ModelOutput (per_atom = False )},
157+ outputs = {"feature " : ModelOutput (sample_kind = "system" )},
156158 interaction_range = CUTOFF ,
157159 supported_devices = ["cpu" , "mps" , "cuda" ],
158160 length_unit = "A" ,
@@ -169,3 +171,12 @@ def requested_neighbor_lists(self) -> List[NeighborListOptions]:
169171cv .eval ()
170172model = AtomisticModel (cv , ModelMetadata (), capabilities )
171173model .save ("vector-global.pt" )
174+
175+
176+ cv = TestCollectiveVariable (
177+ cutoff = CUTOFF , multiple_properties = False , feature_key = "feature/variant"
178+ )
179+ capabilities .outputs = {"feature/variant" : ModelOutput (sample_kind = "system" )}
180+ cv .eval ()
181+ model = AtomisticModel (cv , ModelMetadata (), capabilities )
182+ model .save ("variant-global.pt" )
0 commit comments