-
Notifications
You must be signed in to change notification settings - Fork 0
feat(pt): add atomic_weight parameter to dipole model #2
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
Changes from all commits
26d105e
5d89b4b
2dbd423
02fa9d0
60ac1a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -312,6 +312,7 @@ def eval( | |
| atomic: bool = False, | ||
| fparam: np.ndarray | None = None, | ||
| aparam: np.ndarray | None = None, | ||
| atomic_weight: np.ndarray | None = None, | ||
| **kwargs: Any, | ||
| ) -> dict[str, np.ndarray]: | ||
| """Evaluate the energy, force and virial by using this DP. | ||
|
|
@@ -341,6 +342,12 @@ def eval( | |
| - nframes x natoms x dim_aparam. | ||
| - natoms x dim_aparam. Then all frames are assumed to be provided with the same aparam. | ||
| - dim_aparam. Then all frames and atoms are provided with the same aparam. | ||
| atomic_weight | ||
| The atomic weight for weighted averaging of atomic contributions. | ||
| The array can be of size : | ||
| - nframes x natoms. Different weights for each atom in each frame. | ||
| - nframes x natoms x k. Different weights for each atom in each frame with k dimensions. | ||
| Note: This parameter is currently ignored when spin is provided. | ||
| **kwargs | ||
| Other parameters | ||
|
|
||
|
|
@@ -361,9 +368,19 @@ def eval( | |
| request_defs = self._get_request_defs(atomic) | ||
| if "spin" not in kwargs or kwargs["spin"] is None: | ||
| out = self._eval_func(self._eval_model, numb_test, natoms)( | ||
| coords, cells, atom_types, fparam, aparam, request_defs | ||
| coords, | ||
| cells, | ||
| atom_types, | ||
| fparam, | ||
| aparam, | ||
| atomic_weight, | ||
| request_defs, | ||
| ) | ||
| else: | ||
| if atomic_weight is not None: | ||
| raise ValueError( | ||
| "atomic_weight is not supported when spin is provided." | ||
| ) | ||
| out = self._eval_func(self._eval_model_spin, numb_test, natoms)( | ||
| coords, | ||
| cells, | ||
|
|
@@ -472,6 +489,7 @@ def _eval_model( | |
| atom_types: np.ndarray, | ||
| fparam: np.ndarray | None, | ||
| aparam: np.ndarray | None, | ||
| atomic_weight: np.ndarray | None, | ||
| request_defs: list[OutputVariableDef], | ||
| ) -> tuple[np.ndarray, ...]: | ||
| model = self.dp.to(DEVICE) | ||
|
|
@@ -514,6 +532,15 @@ def _eval_model( | |
| ) | ||
| else: | ||
| aparam_input = None | ||
| if atomic_weight is not None: | ||
| atomic_weight = self._validate_and_reshape_atomic_weight( | ||
| atomic_weight, nframes, natoms | ||
| ) | ||
| atomic_weight_input = to_torch_tensor( | ||
| atomic_weight.reshape(nframes, natoms, -1) | ||
| ) | ||
| else: | ||
| atomic_weight_input = None | ||
|
Comment on lines
+535
to
+543
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Extract duplicated validation logic to a helper method. This validation block is duplicated identically in Extract to a helper method: def _validate_and_reshape_atomic_weight(
self,
atomic_weight: Optional[np.ndarray],
nframes: int,
natoms: int,
) -> Optional[np.ndarray]:
"""Validate and reshape atomic_weight to (nframes, natoms, k).
Parameters
----------
atomic_weight : np.ndarray, optional
Input atomic weight array
nframes : int
Number of frames
natoms : int
Number of atoms
Returns
-------
np.ndarray, optional
Reshaped array of shape (nframes, natoms, k) or None
Raises
------
ValueError
If shape is incompatible with nframes and natoms
"""
if atomic_weight is None:
return None
# Validation logic here...
# (lines 536-574)
return atomic_weight.reshape(nframes, natoms, -1)Then use it in both - if atomic_weight is not None:
- # Validate atomic_weight shape
- if atomic_weight.ndim == 1:
- ...
- atomic_weight_input = to_torch_tensor(
- atomic_weight.reshape(nframes, natoms, -1)
- )
- else:
- atomic_weight_input = None
+ reshaped_weight = self._validate_and_reshape_atomic_weight(
+ atomic_weight, nframes, natoms
+ )
+ atomic_weight_input = to_torch_tensor(reshaped_weight) if reshaped_weight is not None else None🧰 Tools🪛 Ruff (0.14.8)539-541: Avoid specifying long messages outside the exception class (TRY003) 555-557: Avoid specifying long messages outside the exception class (TRY003) 564-566: Avoid specifying long messages outside the exception class (TRY003) 568-570: Avoid specifying long messages outside the exception class (TRY003) 🤖 Prompt for AI Agents |
||
| do_atomic_virial = any( | ||
| x.category == OutputVariableCategory.DERV_C for x in request_defs | ||
| ) | ||
|
|
@@ -524,6 +551,7 @@ def _eval_model( | |
| do_atomic_virial=do_atomic_virial, | ||
| fparam=fparam_input, | ||
| aparam=aparam_input, | ||
| atomic_weight=atomic_weight_input, | ||
| ) | ||
| if isinstance(batch_output, tuple): | ||
| batch_output = batch_output[0] | ||
|
|
@@ -592,6 +620,7 @@ def _eval_model_spin( | |
| ) | ||
| else: | ||
| aparam_input = None | ||
| atomic_weight_input = None | ||
|
|
||
| do_atomic_virial = any( | ||
| x.category == OutputVariableCategory.DERV_C_REDU for x in request_defs | ||
|
|
@@ -604,6 +633,7 @@ def _eval_model_spin( | |
| do_atomic_virial=do_atomic_virial, | ||
| fparam=fparam_input, | ||
| aparam=aparam_input, | ||
| atomic_weight=atomic_weight_input, | ||
| ) | ||
| if isinstance(batch_output, tuple): | ||
| batch_output = batch_output[0] | ||
|
|
@@ -847,3 +877,60 @@ def eval_fitting_last_layer( | |
| fitting_net = model.eval_fitting_last_layer() | ||
| model.set_eval_fitting_last_layer_hook(False) | ||
| return to_numpy_array(fitting_net) | ||
|
|
||
| def _validate_and_reshape_atomic_weight( | ||
| self, | ||
| atomic_weight: np.ndarray, | ||
| nframes: int, | ||
| natoms: int, | ||
| ) -> np.ndarray: | ||
| """Validate and reshape atomic_weight to (nframes, natoms, k). | ||
|
|
||
| Parameters | ||
| ---------- | ||
| atomic_weight : np.ndarray | ||
| Input atomic weights with various possible shapes | ||
| nframes : int | ||
| Number of frames | ||
| natoms : int | ||
| Number of atoms | ||
|
|
||
| Returns | ||
| ------- | ||
| np.ndarray | ||
| Reshaped atomic_weight with shape (nframes, natoms, k) | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If atomic_weight shape is incompatible | ||
| """ | ||
| # Validate atomic_weight shape | ||
| if atomic_weight.ndim == 1: | ||
| # (natoms,) - broadcast across frames | ||
| if atomic_weight.shape[0] != natoms: | ||
| raise ValueError( | ||
| f"atomic_weight shape {atomic_weight.shape} incompatible with number of atoms {natoms}" | ||
| ) | ||
| atomic_weight = np.tile(atomic_weight, (nframes, 1)) | ||
| elif atomic_weight.ndim == 2: | ||
| # (nframes, natoms) or (natoms, k) | ||
| if atomic_weight.shape[0] == natoms and atomic_weight.shape[1] != nframes: | ||
| # (natoms, k) - broadcast across frames | ||
| atomic_weight = np.tile(atomic_weight, (nframes, 1, 1)) | ||
| elif atomic_weight.shape[0] != nframes or atomic_weight.shape[1] != natoms: | ||
| raise ValueError( | ||
| f"atomic_weight shape {atomic_weight.shape} incompatible with nframes={nframes} and natoms={natoms}" | ||
| ) | ||
| elif atomic_weight.ndim == 3: | ||
| # (nframes, natoms, k) | ||
| if atomic_weight.shape[0] != nframes or atomic_weight.shape[1] != natoms: | ||
| raise ValueError( | ||
| f"atomic_weight shape {atomic_weight.shape} incompatible with nframes={nframes} and natoms={natoms}" | ||
| ) | ||
| else: | ||
| raise ValueError( | ||
| f"atomic_weight must have 1, 2, or 3 dimensions, got {atomic_weight.ndim}" | ||
| ) | ||
|
|
||
| return atomic_weight | ||
Uh oh!
There was an error while loading. Please reload this page.