| |
|
|
| from typing import List, Dict, Union |
| import torch |
|
|
| from onescience.utils.nequip.internal.global_dtype import _GLOBAL_DTYPE |
|
|
|
|
| |
| |
| |
| |
|
|
|
|
| def cutoff_partialdict_to_fulldict( |
| partial_dict: Dict[str, Union[float, Dict[str, float]]], |
| type_names: List[str], |
| r_max: float, |
| ) -> Dict[str, Dict[str, float]]: |
| """Convert partial cutoff dict to full dict with all entries. |
| |
| Fills missing entries with ``r_max``. |
| |
| Args: |
| partial_dict: partial specification from config, |
| e.g. ``{"H": 2.0, "C": {"H": 4.0, "C": 3.5}}`` |
| type_names: list of atom type names |
| r_max: global cutoff radius (default for missing entries) |
| |
| Returns: |
| full dict with all source -> target pairs specified, |
| e.g. ``{"H": {"H": 2.0, "C": 2.0}, "C": {"H": 4.0, "C": 3.5}}`` |
| """ |
| full_dict = {} |
| for source_type in type_names: |
| full_dict[source_type] = {} |
| if source_type in partial_dict: |
| entry = partial_dict[source_type] |
| if isinstance(entry, float): |
| |
| for target_type in type_names: |
| full_dict[source_type][target_type] = entry |
| else: |
| |
| for target_type in type_names: |
| if target_type in entry: |
| full_dict[source_type][target_type] = entry[target_type] |
| else: |
| |
| full_dict[source_type][target_type] = r_max |
| else: |
| |
| for target_type in type_names: |
| full_dict[source_type][target_type] = r_max |
|
|
| return full_dict |
|
|
|
|
| def cutoff_fulldict_to_tensor( |
| full_dict: Dict[str, Dict[str, float]], |
| type_names: List[str], |
| ) -> torch.Tensor: |
| """Convert full cutoff dict to tensor. |
| |
| Args: |
| full_dict: full specification with all source -> target pairs |
| type_names: list of atom type names |
| |
| Returns: |
| tensor of shape ``(num_types, num_types)`` with per-edge-type cutoffs |
| """ |
| num_types = len(type_names) |
| cutoff_list = [] |
| for source_type in type_names: |
| row = [] |
| for target_type in type_names: |
| row.append(full_dict[source_type][target_type]) |
| cutoff_list.append(row) |
|
|
| cutoff_tensor = torch.as_tensor(cutoff_list, dtype=_GLOBAL_DTYPE).contiguous() |
| assert cutoff_tensor.shape == (num_types, num_types) |
| assert torch.all(cutoff_tensor > 0) |
| return cutoff_tensor |
|
|
|
|
| def cutoff_tensor_to_str(cutoff_tensor: torch.Tensor) -> str: |
| """Convert tensor to metadata string format. |
| |
| Args: |
| cutoff_tensor: cutoff values as tensor (any shape, will be flattened) |
| |
| Returns: |
| space-separated string of cutoff values in row-major order |
| """ |
| return " ".join(str(r.item()) for r in cutoff_tensor.reshape(-1)) |
|
|
|
|
| def cutoff_str_to_fulldict( |
| cutoff_str: str, |
| type_names: List[str], |
| ) -> Dict[str, Dict[str, float]]: |
| """Convert metadata string to full dict format. |
| |
| Args: |
| cutoff_str: space-separated string of cutoff values |
| type_names: list of atom type names |
| |
| Returns: |
| full dict with all source -> target pairs specified |
| """ |
| if cutoff_str in ("", None): |
| return None |
|
|
| cutoff_values = [float(x) for x in cutoff_str.split()] |
| num_types = len(type_names) |
|
|
| assert len(cutoff_values) == num_types * num_types, ( |
| f"Expected {num_types * num_types} cutoff values, got {len(cutoff_values)}" |
| ) |
|
|
| full_dict = {} |
| for i, source_type in enumerate(type_names): |
| full_dict[source_type] = {} |
| for j, target_type in enumerate(type_names): |
| full_dict[source_type][target_type] = cutoff_values[i * num_types + j] |
|
|
| return full_dict |
|
|
|
|
| def cutoff_partialdict_to_tensor( |
| partial_dict: Dict[str, Union[float, Dict[str, float]]], |
| type_names: List[str], |
| r_max: float, |
| ) -> torch.Tensor: |
| """Composes ``cutoff_partialdict_to_fulldict`` and ``cutoff_fulldict_to_tensor``.""" |
| full_dict = cutoff_partialdict_to_fulldict(partial_dict, type_names, r_max) |
| cutoff_tensor = cutoff_fulldict_to_tensor(full_dict, type_names) |
| assert torch.all(cutoff_tensor <= r_max) |
| return cutoff_tensor |
|
|
|
|
| def cutoff_partialdict_to_str( |
| partial_dict: Dict[str, Union[float, Dict[str, float]]], |
| type_names: List[str], |
| r_max: float, |
| ) -> str: |
| """Composes ``cutoff_partialdict_to_fulldict``, ``cutoff_fulldict_to_tensor``, and ``cutoff_tensor_to_str``.""" |
| full_dict = cutoff_partialdict_to_fulldict(partial_dict, type_names, r_max) |
| tensor = cutoff_fulldict_to_tensor(full_dict, type_names) |
| return cutoff_tensor_to_str(tensor) |
|
|