OneScience commited on
Commit
24d7cbe
·
verified ·
1 Parent(s): 554f15c

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -1,35 +1,47 @@
1
  *.7z filter=lfs diff=lfs merge=lfs -text
2
  *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
 
4
  *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
  *.ftz filter=lfs diff=lfs merge=lfs -text
7
  *.gz filter=lfs diff=lfs merge=lfs -text
8
  *.h5 filter=lfs diff=lfs merge=lfs -text
9
  *.joblib filter=lfs diff=lfs merge=lfs -text
10
  *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
  *.model filter=lfs diff=lfs merge=lfs -text
13
  *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
  *.onnx filter=lfs diff=lfs merge=lfs -text
17
  *.ot filter=lfs diff=lfs merge=lfs -text
18
  *.parquet filter=lfs diff=lfs merge=lfs -text
19
  *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
  *.pt filter=lfs diff=lfs merge=lfs -text
23
  *.pth filter=lfs diff=lfs merge=lfs -text
24
  *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
  *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
  *.tflite filter=lfs diff=lfs merge=lfs -text
30
  *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
  *.xz filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
  *.7z filter=lfs diff=lfs merge=lfs -text
2
  *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bin.* filter=lfs diff=lfs merge=lfs -text
5
  *.bz2 filter=lfs diff=lfs merge=lfs -text
 
6
  *.ftz filter=lfs diff=lfs merge=lfs -text
7
  *.gz filter=lfs diff=lfs merge=lfs -text
8
  *.h5 filter=lfs diff=lfs merge=lfs -text
9
  *.joblib filter=lfs diff=lfs merge=lfs -text
10
  *.lfs.* filter=lfs diff=lfs merge=lfs -text
 
11
  *.model filter=lfs diff=lfs merge=lfs -text
12
  *.msgpack filter=lfs diff=lfs merge=lfs -text
 
 
13
  *.onnx filter=lfs diff=lfs merge=lfs -text
14
  *.ot filter=lfs diff=lfs merge=lfs -text
15
  *.parquet filter=lfs diff=lfs merge=lfs -text
16
  *.pb filter=lfs diff=lfs merge=lfs -text
 
 
17
  *.pt filter=lfs diff=lfs merge=lfs -text
18
  *.pth filter=lfs diff=lfs merge=lfs -text
19
  *.rar filter=lfs diff=lfs merge=lfs -text
 
20
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
21
  *.tar.* filter=lfs diff=lfs merge=lfs -text
 
22
  *.tflite filter=lfs diff=lfs merge=lfs -text
23
  *.tgz filter=lfs diff=lfs merge=lfs -text
 
24
  *.xz filter=lfs diff=lfs merge=lfs -text
25
  *.zip filter=lfs diff=lfs merge=lfs -text
26
+ *.zstandard filter=lfs diff=lfs merge=lfs -text
27
+ *.tfevents* filter=lfs diff=lfs merge=lfs -text
28
+ *.db* filter=lfs diff=lfs merge=lfs -text
29
+ *.ark* filter=lfs diff=lfs merge=lfs -text
30
+ **/*ckpt*data* filter=lfs diff=lfs merge=lfs -text
31
+ **/*ckpt*.meta filter=lfs diff=lfs merge=lfs -text
32
+ **/*ckpt*.index filter=lfs diff=lfs merge=lfs -text
33
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
34
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
35
+ *.gguf* filter=lfs diff=lfs merge=lfs -text
36
+ *.ggml filter=lfs diff=lfs merge=lfs -text
37
+ *.llamafile* filter=lfs diff=lfs merge=lfs -text
38
+ *.pt2 filter=lfs diff=lfs merge=lfs -text
39
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
40
+ *.npy filter=lfs diff=lfs merge=lfs -text
41
+ *.npz filter=lfs diff=lfs merge=lfs -text
42
+ *.pickle filter=lfs diff=lfs merge=lfs -text
43
+ *.pkl filter=lfs diff=lfs merge=lfs -text
44
+ *.tar filter=lfs diff=lfs merge=lfs -text
45
+ *.wasm filter=lfs diff=lfs merge=lfs -text
46
  *.zst filter=lfs diff=lfs merge=lfs -text
47
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p align="center">
2
+ <strong>
3
+ <span style="font-size: 30px;">MatterSim</span>
4
+ </strong>
5
+ </p>
6
+
7
+ # Model Introduction
8
+
9
+ MatterSim is a deep-learning interatomic potential model across elements, temperatures, and pressures proposed by Microsoft Research. It predicts energy and forces for inorganic materials, molecules, and periodic systems.
10
+
11
+ Paper: *MatterSim: A deep-learning atomistic model across elements, temperatures, and pressures*
12
+ Reference implementation: https://github.com/microsoft/mattersim
13
+
14
+ # Model Description
15
+
16
+ MatterSim is based on a deep-learning architecture and is trained on multiple materials and molecular datasets. It performs energy and force prediction, structure relaxation, molecular dynamics, and custom-dataset fine-tuning for inorganic materials, molecules, and periodic systems.
17
+
18
+ # Applicable Scenarios
19
+
20
+ | Scenario | Description |
21
+ | :---: | :--- |
22
+ | Single-point energy/force prediction | Quickly predict energy and atomic forces for a given atomic structure |
23
+ | Batch structure inference | Perform batch energy/force prediction for multiple structures |
24
+ | Structure relaxation | Optimize atomic positions and unit-cell shape using FIRE/BFGS |
25
+ | Molecular dynamics | Run short-range MD sampling under the NVT ensemble |
26
+ | Custom data fine-tuning | Fine-tune a pre-trained MatterSim model on your own dataset |
27
+ | Environment connectivity check | Use the single-point/relaxation scripts to check the OneScience matchem environment, model loading, and CUDA/DCU availability |
28
+
29
+ # Usage Instructions
30
+
31
+ ## 1. Using OneCode
32
+
33
+ You can try out intelligent one-click AI4S programming in the OneCode online environment:
34
+
35
+ [Try intelligent one-click AI4S programming](https://web-2069360198568017922-iaaj.ksai.scnet.cn:58043/home)
36
+
37
+ ## 2. Manual Installation and Usage
38
+
39
+ **Hardware Requirements**
40
+
41
+ - GPU or DCU is recommended.
42
+ - CPU can be used for import and small-configuration connectivity checks; full training and inference will be slow.
43
+ - DCU users need to install DTK in advance. DTK 25.04.2 or above, or the OneScience-recommended version matching the current cluster, is suggested.
44
+
45
+ ### Download the Model Package
46
+
47
+ ```bash
48
+ modelscope download --model OneScience/Mattersim --local_dir ./mattersim
49
+ cd mattersim
50
+ ```
51
+
52
+ ### Install the Runtime Environment
53
+
54
+ **DCU Environment**
55
+
56
+ ```bash
57
+ # Please activate DTK and CONDA first
58
+ conda create -n onescience311 python=3.11 -y
59
+ conda activate onescience311
60
+ # uv installation is also supported
61
+ pip install onescience[matchem-dcu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
62
+ ```
63
+
64
+ **GPU Environment**
65
+
66
+ ```bash
67
+ # Please activate CONDA first
68
+ conda create -n onescience311 python=3.11 -y libstdcxx-ng=12 libgcc-ng=12 gcc_linux-64=12 gxx_linux-64=12
69
+ conda activate onescience311
70
+ # uv installation is also supported
71
+ pip install onescience[matchem-gpu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
72
+ ```
73
+
74
+
75
+ ### Training Data Description
76
+
77
+ By default, this repository only includes the example data file `high_level_water.xyz`, used for quickly verifying model loading, single-point inference, structure relaxation, molecular dynamics, and fine-tuning workflows. For other training data, please download it yourself and place it in the `data/` directory.
78
+
79
+ ### Training Weights
80
+
81
+ The repository includes `weight/mattersim-v1.0.0-1M.pth`. All scripts also support specifying model weights via `--checkpoint`.
82
+
83
+ ### Inference
84
+
85
+ ```bash
86
+ cd scripts
87
+ python single_point.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth
88
+ ```
89
+
90
+ ```bash
91
+ cd scripts
92
+ python batch_inference.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth
93
+ ```
94
+
95
+ **Structure Relaxation**
96
+
97
+ ```bash
98
+ cd scripts
99
+ python relax.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth --device cuda
100
+ ```
101
+
102
+ > The default weight is `../weight/mattersim-v1.0.0-1M.pth`.
103
+
104
+ **Molecular Dynamics**
105
+
106
+ ```bash
107
+ cd scripts
108
+ python md.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth --device cuda
109
+ ```
110
+
111
+ > The default weight is also `../weight/mattersim-v1.0.0-1M.pth`.
112
+
113
+ ### Fine-tuning
114
+
115
+ Edit the paths and parameters in `scripts/finetune_config.yaml` directly (e.g., `train_data_path`, `checkpoint`, etc.):
116
+
117
+ ```bash
118
+ cd scripts
119
+ # Edit fields such as train_data_path and checkpoint in finetune_config.yaml
120
+ ```
121
+
122
+ Single-GPU:
123
+
124
+ ```bash
125
+ python finetune.py --config finetune_config.yaml
126
+ ```
127
+
128
+ Multi-GPU DDP:
129
+
130
+ ```bash
131
+ torchrun --nproc_per_node=4 finetune.py --config finetune_config.yaml
132
+ ```
133
+
134
+ # OneScience Official Information
135
+
136
+ | Platform | OneScience Main Repository | Skills Repository |
137
+ | --- | --- | --- |
138
+ | Gitee | https://gitee.com/onescience-ai/onescience | https://gitee.com/onescience-ai/oneskills |
139
+ | GitHub | https://github.com/onescience-ai/OneScience | https://github.com/onescience-ai/oneskills |
140
+
141
+ ---
142
+
143
+ # Citation and License
144
+
145
+ - The MatterSim-related code comes from the matchem example implementation in the OneScience project and references the upstream MatterSim project (https://github.com/microsoft/mattersim). The upstream MatterSim code is released under the [MIT License](https://github.com/microsoft/mattersim/blob/main/LICENSE).
146
+ - If you use MatterSim training or inference results in scientific research, we recommend citing the original MatterSim paper, the relevant OneScience project information, and the sources of the datasets actually used.
configuration.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"framework":"Pytorch","task":"other"}
data/high_level_water.xyz ADDED
The diff for this file is too large to render. See raw diff
 
model/__init__.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """MatterSim model and integration entry points."""
2
+
3
+ MATTERSIM_SOURCE_VERSION = "1.2.3"
4
+ MATTERSIM_INTEGRATION_VERSION = "dcu2"
5
+
6
+ from .adapter import (
7
+ DEFAULT_CHECKPOINT,
8
+ load_calculator,
9
+ load_potential,
10
+ predict_structures,
11
+ resolve_checkpoint,
12
+ )
13
+ __all__ = [
14
+ "DEFAULT_CHECKPOINT",
15
+ "M3Gnet",
16
+ "MATTERSIM_INTEGRATION_VERSION",
17
+ "MATTERSIM_SOURCE_VERSION",
18
+ "MatterSim",
19
+ "load_calculator",
20
+ "load_potential",
21
+ "predict_structures",
22
+ "resolve_checkpoint",
23
+ ]
24
+
25
+
26
+ def __getattr__(name):
27
+ if name in {"M3Gnet", "MatterSim"}:
28
+ from .mattersim import M3Gnet, MatterSim
29
+
30
+ return {"M3Gnet": M3Gnet, "MatterSim": MatterSim}[name]
31
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
model/adapter.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Checkpoint and model factories for the OneScience MatterSim integration."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+
6
+ import torch
7
+
8
+ DEFAULT_CHECKPOINT = "mattersim-v1.0.0-1M.pth"
9
+
10
+
11
+ def resolve_checkpoint(checkpoint: str | os.PathLike | None = None) -> str:
12
+ """Resolve a MatterSim checkpoint without changing its native format.
13
+
14
+ Explicit checkpoint values are passed through so MatterSim model aliases keep
15
+ working. When no value is supplied, the shared OneScience model store is
16
+ checked before falling back to MatterSim's native alias and download logic.
17
+ """
18
+ if checkpoint is not None:
19
+ return str(Path(checkpoint).expanduser())
20
+
21
+ models_dir = os.environ.get("ONESCIENCE_MODELS_DIR")
22
+ if models_dir:
23
+ shared_checkpoint = Path(models_dir).expanduser() / "mattersim" / DEFAULT_CHECKPOINT
24
+ if shared_checkpoint.is_file():
25
+ return str(shared_checkpoint)
26
+
27
+ return DEFAULT_CHECKPOINT
28
+
29
+
30
+ def _device(device: str | None) -> str:
31
+ return device or ("cuda" if torch.cuda.is_available() else "cpu")
32
+
33
+
34
+ def load_potential(
35
+ checkpoint: str | os.PathLike | None = None,
36
+ device: str | None = None,
37
+ load_training_state: bool = False,
38
+ **kwargs,
39
+ ):
40
+ """Load a MatterSim ``Potential`` from a resolved checkpoint."""
41
+ from onescience.utils.mattersim.potential import Potential
42
+
43
+ return Potential.from_checkpoint(
44
+ load_path=resolve_checkpoint(checkpoint),
45
+ device=_device(device),
46
+ load_training_state=load_training_state,
47
+ **kwargs,
48
+ )
49
+
50
+
51
+ def load_calculator(
52
+ checkpoint: str | os.PathLike | None = None,
53
+ device: str | None = None,
54
+ **kwargs,
55
+ ):
56
+ """Create an ASE-compatible ``MatterSimCalculator``."""
57
+ from onescience.utils.mattersim.calculator import MatterSimCalculator
58
+
59
+ return MatterSimCalculator.from_checkpoint(
60
+ resolve_checkpoint(checkpoint), device=_device(device), **kwargs
61
+ )
62
+
63
+
64
+ def predict_structures(
65
+ atoms,
66
+ checkpoint: str | os.PathLike | None = None,
67
+ device: str | None = None,
68
+ batch_size: int = 16,
69
+ include_forces: bool = True,
70
+ include_stresses: bool = False,
71
+ cutoff: float = 5.0,
72
+ threebody_cutoff: float = 4.0,
73
+ ):
74
+ """Predict ASE structures with the MatterSim potential."""
75
+ from onescience.datapipes.materials.mattersim import build_dataloader
76
+
77
+ potential = load_potential(checkpoint=checkpoint, device=device)
78
+ dataloader = build_dataloader(
79
+ atoms=list(atoms),
80
+ batch_size=batch_size,
81
+ cutoff=cutoff,
82
+ threebody_cutoff=threebody_cutoff,
83
+ only_inference=True,
84
+ )
85
+ energies, forces, stresses = potential.predict_properties(
86
+ dataloader,
87
+ include_forces=include_forces,
88
+ include_stresses=include_stresses,
89
+ )
90
+ return {
91
+ "energies": energies,
92
+ "forces": forces,
93
+ "stresses": stresses,
94
+ }
model/mattersim.py ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ from typing import Dict
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+ from torch_runstats.scatter import scatter
8
+
9
+ from onescience.modules.block.mattersim_block import MainBlock
10
+ from onescience.modules.embedding.mattersim_embedding import (
11
+ SmoothBesselBasis,
12
+ SphericalBasisLayer,
13
+ )
14
+ from onescience.modules.func_utils.mattersim_jit import compile_mode
15
+ from onescience.modules.func_utils.mattersim_scaling import AtomScaling
16
+ from onescience.modules.layer.mattersim_layer import GatedMLP, MLP
17
+
18
+
19
+ @compile_mode("script")
20
+ class M3Gnet(nn.Module):
21
+ """
22
+ M3Gnet
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ num_blocks: int = 4,
28
+ units: int = 128,
29
+ max_l: int = 4,
30
+ max_n: int = 4,
31
+ cutoff: float = 5.0,
32
+ device: str = "cuda" if torch.cuda.is_available() else "cpu",
33
+ max_z: int = 94,
34
+ threebody_cutoff: float = 4.0,
35
+ **kwargs,
36
+ ):
37
+ super().__init__()
38
+ self.rbf = SmoothBesselBasis(r_max=cutoff, max_n=max_n)
39
+ self.sbf = SphericalBasisLayer(max_n=max_n, max_l=max_l, cutoff=cutoff)
40
+ self.edge_encoder = MLP(
41
+ in_dim=max_n, out_dims=[units], activation="swish", use_bias=False
42
+ )
43
+ module_list = [
44
+ MainBlock(max_n, max_l, cutoff, units, max_n, threebody_cutoff)
45
+ for i in range(num_blocks)
46
+ ]
47
+ self.graph_conv = nn.ModuleList(module_list)
48
+ self.final = GatedMLP(
49
+ in_dim=units,
50
+ out_dims=[units, units, 1],
51
+ activation=["swish", "swish", None],
52
+ )
53
+ self.apply(self.init_weights)
54
+ self.atom_embedding = MLP(
55
+ in_dim=max_z + 1, out_dims=[units], activation=None, use_bias=False
56
+ )
57
+ self.atom_embedding.apply(self.init_weights_uniform)
58
+ self.normalizer = AtomScaling(verbose=False, max_z=max_z, device=device)
59
+ self.max_z = max_z
60
+ self.device = device
61
+ self.model_args = {
62
+ "num_blocks": num_blocks,
63
+ "units": units,
64
+ "max_l": max_l,
65
+ "max_n": max_n,
66
+ "cutoff": cutoff,
67
+ "max_z": max_z,
68
+ "threebody_cutoff": threebody_cutoff,
69
+ }
70
+
71
+ def forward(
72
+ self,
73
+ input: Dict[str, torch.Tensor],
74
+ dataset_idx: int = -1,
75
+ ) -> torch.Tensor:
76
+ # Exact data from input_dictionary
77
+ pos = input["atom_pos"]
78
+ cell = input["cell"]
79
+ pbc_offsets = input["pbc_offsets"].float()
80
+ atom_attr = input["atom_attr"]
81
+ edge_index = input["edge_index"].long()
82
+ three_body_indices = input["three_body_indices"].long()
83
+ num_bonds = input["num_bonds"]
84
+ num_triple_ij = input["num_triple_ij"]
85
+ num_atoms = input["num_atoms"]
86
+ num_graphs = input["num_graphs"]
87
+ batch = input["batch"]
88
+
89
+ # Use precomputed values if available, otherwise compute on the fly
90
+ # (backward-compat for callers not using batch_to_dict)
91
+ total_num_atoms = input.get("total_num_atoms", int(num_atoms.sum()))
92
+ total_num_bonds = input.get("total_num_bonds", int(num_bonds.sum()))
93
+
94
+ bond_index_bias = input.get("bond_index_bias", None)
95
+ if bond_index_bias is None:
96
+ cumsum = torch.cumsum(num_bonds, dim=0) - num_bonds
97
+ bond_index_bias = torch.repeat_interleave(
98
+ cumsum, input["num_three_body"], dim=0
99
+ ).unsqueeze(-1)
100
+
101
+ three_body_edge_map = input.get("three_body_edge_map", None)
102
+
103
+ # -------------------------------------------------------------#
104
+ three_body_indices = three_body_indices + bond_index_bias
105
+
106
+ # === Refer to the implementation of M3GNet, ===
107
+ # === we should re-compute the following attributes ===
108
+ # edge_length, edge_vector(optional), triple_edge_length, theta_jik
109
+ edge_batch = batch[edge_index[0]]
110
+ edge_vector = pos[edge_index[0]] - (
111
+ pos[edge_index[1]]
112
+ + torch.einsum("bi, bij->bj", pbc_offsets, cell[edge_batch])
113
+ )
114
+ edge_length = torch.linalg.norm(edge_vector, dim=1)
115
+ vij = edge_vector[three_body_indices[:, 0].clone()]
116
+ vik = edge_vector[three_body_indices[:, 1].clone()]
117
+ rij = edge_length[three_body_indices[:, 0].clone()]
118
+ rik = edge_length[three_body_indices[:, 1].clone()]
119
+ cos_jik = torch.sum(vij * vik, dim=1) / (rij * rik)
120
+ # eps = 1e-7 avoid nan in torch.acos function
121
+ cos_jik = torch.clamp(cos_jik, min=-1.0 + 1e-7, max=1.0 - 1e-7)
122
+ triple_edge_length = rik.view(-1)
123
+ edge_length = edge_length.unsqueeze(-1)
124
+ atomic_numbers = atom_attr.squeeze(1).long()
125
+
126
+ # featurize
127
+ atom_attr = self.atom_embedding(self.one_hot_atoms(atomic_numbers))
128
+ edge_attr = self.rbf(edge_length.view(-1))
129
+ edge_attr_zero = edge_attr # e_ij^0
130
+ edge_attr = self.edge_encoder(edge_attr)
131
+ three_basis = self.sbf(triple_edge_length, torch.acos(cos_jik))
132
+
133
+ # Main Loop
134
+ for idx, conv in enumerate(self.graph_conv):
135
+ atom_attr, edge_attr = conv(
136
+ atom_attr,
137
+ edge_attr,
138
+ edge_attr_zero,
139
+ edge_index,
140
+ three_basis,
141
+ three_body_indices,
142
+ edge_length,
143
+ num_bonds,
144
+ num_triple_ij,
145
+ num_atoms,
146
+ total_num_atoms=total_num_atoms,
147
+ total_num_bonds=total_num_bonds,
148
+ three_body_edge_map=three_body_edge_map,
149
+ )
150
+
151
+ energies_i = self.final(atom_attr).view(-1) # [batch_size*num_atoms]
152
+ energies_i = self.normalizer(energies_i, atomic_numbers)
153
+ energies = scatter(energies_i, batch, dim=0, dim_size=num_graphs)
154
+
155
+ return energies # [batch_size]
156
+
157
+ def init_weights(self, m):
158
+ if isinstance(m, nn.Linear):
159
+ torch.nn.init.xavier_uniform_(m.weight)
160
+
161
+ def init_weights_uniform(self, m):
162
+ if isinstance(m, nn.Linear):
163
+ torch.nn.init.uniform_(m.weight, a=-0.05, b=0.05)
164
+
165
+ @torch.jit.export
166
+ def one_hot_atoms(self, species):
167
+ # one_hots = []
168
+ # for i in range(species.shape[0]):
169
+ # one_hots.append(
170
+ # F.one_hot(
171
+ # species[i],
172
+ # num_classes=self.max_z+1).float().to(species.device)
173
+ # )
174
+ # return torch.cat(one_hots, dim=0)
175
+ return F.one_hot(species, num_classes=self.max_z + 1).float()
176
+
177
+ def print(self):
178
+ from prettytable import PrettyTable
179
+
180
+ table = PrettyTable(["Modules", "Parameters"])
181
+ total_params = 0
182
+ for name, parameter in self.named_parameters():
183
+ if not parameter.requires_grad:
184
+ continue
185
+ params = parameter.numel()
186
+ table.add_row([name, params])
187
+ total_params += params
188
+ print(table)
189
+ print(f"Total Trainable Params: {total_params}")
190
+
191
+ @torch.jit.export
192
+ def set_normalizer(self, normalizer: AtomScaling):
193
+ self.normalizer = normalizer
194
+
195
+ def get_model_args(self):
196
+ return self.model_args
197
+
198
+
199
+ MatterSim = M3Gnet
200
+
201
+ __all__ = ["M3Gnet", "MatterSim"]
scripts/batch_inference.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+
3
+ from ase.build import bulk
4
+
5
+ from onescience.models.mattersim import predict_structures
6
+
7
+
8
+ def main() -> None:
9
+ parser = argparse.ArgumentParser(description="MatterSim batch inference")
10
+ parser.add_argument("--checkpoint")
11
+ parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
12
+ parser.add_argument("--batch-size", type=int, default=16)
13
+ args = parser.parse_args()
14
+
15
+ structures = [bulk("Si", "diamond", a=a) for a in (5.40, 5.43, 5.46)]
16
+ result = predict_structures(
17
+ structures,
18
+ checkpoint=args.checkpoint,
19
+ device=args.device,
20
+ batch_size=args.batch_size,
21
+ )
22
+ for index, (energy, forces) in enumerate(
23
+ zip(result["energies"], result["forces"], strict=True)
24
+ ):
25
+ print(
26
+ f"Structure {index}: energy={energy:.6f} eV, "
27
+ f"max_force={abs(forces).max():.6e} eV/angstrom"
28
+ )
29
+
30
+
31
+ if __name__ == "__main__":
32
+ main()
scripts/finetune.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from pathlib import Path
3
+
4
+ import yaml
5
+
6
+ from onescience.utils.mattersim import FineTuneConfig, MatterSimTrainer
7
+
8
+
9
+ def _load_yaml_config(path: str) -> dict:
10
+ with open(path, "r", encoding="utf-8") as stream:
11
+ return yaml.safe_load(stream) or {}
12
+
13
+
14
+ def _build_parser(base_config: dict) -> argparse.ArgumentParser:
15
+ parser = argparse.ArgumentParser(description="Fine-tune MatterSim with OneScience")
16
+ parser.add_argument("--config", help="Path to YAML config file")
17
+ parser.add_argument(
18
+ "--train-data-path", default=base_config.get("train_data_path")
19
+ )
20
+ parser.add_argument(
21
+ "--valid-data-path", default=base_config.get("valid_data_path")
22
+ )
23
+ parser.add_argument("--checkpoint", default=base_config.get("checkpoint"))
24
+ parser.add_argument("--save-path", default=base_config.get("save_path", "./results/mattersim"))
25
+ parser.add_argument("--run-name", default=base_config.get("run_name", "onescience-mattersim"))
26
+ parser.add_argument("--epochs", type=int, default=base_config.get("epochs", 1000))
27
+ parser.add_argument("--batch-size", type=int, default=base_config.get("batch_size", 16))
28
+ parser.add_argument("--lr", type=float, default=base_config.get("lr", 2e-4))
29
+ parser.add_argument(
30
+ "--device", choices=("cpu", "cuda"), default=base_config.get("device", "cuda")
31
+ )
32
+ parser.add_argument("--seed", type=int, default=base_config.get("seed", 42))
33
+ parser.add_argument(
34
+ "--include-stresses",
35
+ action="store_true",
36
+ default=base_config.get("include_stresses", False),
37
+ )
38
+ parser.add_argument(
39
+ "--no-include-forces",
40
+ action="store_false",
41
+ dest="include_forces",
42
+ default=base_config.get("include_forces", True),
43
+ )
44
+ parser.add_argument(
45
+ "--re-normalize",
46
+ action="store_true",
47
+ default=base_config.get("re_normalize", False),
48
+ )
49
+ parser.add_argument(
50
+ "--no-save-checkpoint",
51
+ action="store_false",
52
+ dest="save_checkpoint",
53
+ default=base_config.get("save_checkpoint", True),
54
+ )
55
+ return parser
56
+
57
+
58
+ def main() -> None:
59
+ # Two-phase parsing: first get --config, then use YAML defaults for the rest.
60
+ pre_parser = argparse.ArgumentParser(add_help=False)
61
+ pre_parser.add_argument("--config")
62
+ pre_args, remaining = pre_parser.parse_known_args()
63
+
64
+ base_config = _load_yaml_config(pre_args.config) if pre_args.config else {}
65
+ parser = _build_parser(base_config)
66
+ args = parser.parse_args(remaining)
67
+
68
+ # Drop None values and the config key itself.
69
+ kwargs = {k: v for k, v in vars(args).items() if v is not None and k != "config"}
70
+ MatterSimTrainer(FineTuneConfig(**kwargs)).fit()
71
+
72
+
73
+ if __name__ == "__main__":
74
+ main()
scripts/finetune_config.yaml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MatterSim 微调基础配置
2
+ # 请复制此文件后,修改下方带 "TODO:" 标记的路径为你本地实际路径。
3
+
4
+ # 数据路径(TODO: 修改为你的训练数据路径)
5
+ # 示例使用仓库自带的 data/high_level_water.xyz
6
+ train_data_path: ../data/high_level_water.xyz
7
+
8
+ # 验证数据路径,不需要可保持 null(TODO: 按需修改)
9
+ valid_data_path: null
10
+
11
+ # checkpoint 路径(TODO: 修改为你的预训练模型路径)
12
+ # 示例使用仓库自带的 weight/mattersim-v1.0.0-1M.pth
13
+ checkpoint: ../weight/mattersim-v1.0.0-1M.pth
14
+
15
+ # 输出设置
16
+ save_path: ./results/mattersim
17
+ run_name: onescience-mattersim
18
+
19
+ # 训练超参数
20
+ epochs: 1
21
+ batch_size: 16
22
+ lr: 2.0e-4
23
+ seed: 42
24
+
25
+ # 设备:cuda 或 cpu,留空则自动检测
26
+ device: cuda
27
+
28
+ # 训练目标
29
+ cutoff: 5.0
30
+ threebody_cutoff: 4.0
31
+ include_forces: true
32
+ include_stresses: false
33
+
34
+ # 损失权重
35
+ force_loss_ratio: 1.0
36
+ stress_loss_ratio: 0.1
37
+
38
+ # 保存与早停
39
+ save_checkpoint: true
40
+ ckpt_interval: 10
41
+ early_stop_patience: 10
42
+
43
+ # 重新归一化(可选)
44
+ re_normalize: false
scripts/md.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+
3
+ from ase.build import bulk
4
+
5
+ from onescience.utils.mattersim import molecular_dynamics
6
+
7
+
8
+ parser = argparse.ArgumentParser(description="MatterSim molecular dynamics")
9
+ parser.add_argument(
10
+ "--checkpoint",
11
+ default="../weight/mattersim-v1.0.0-1M.pth",
12
+ help="Path to MatterSim checkpoint",
13
+ )
14
+ parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
15
+ args = parser.parse_args()
16
+
17
+ atoms = bulk("Si", "diamond", a=5.43).repeat((2, 2, 2))
18
+ dynamics = molecular_dynamics(
19
+ atoms,
20
+ checkpoint=args.checkpoint,
21
+ ensemble="nvt_berendsen",
22
+ temperature=300,
23
+ timestep=1.0,
24
+ logfile="-",
25
+ device=args.device,
26
+ )
27
+ dynamics.run(10)
scripts/relax.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+
3
+ from ase.build import bulk
4
+
5
+ from onescience.utils.mattersim import relax
6
+
7
+
8
+ parser = argparse.ArgumentParser(description="MatterSim structure relaxation")
9
+ parser.add_argument(
10
+ "--checkpoint",
11
+ default="../weight/mattersim-v1.0.0-1M.pth",
12
+ help="Path to MatterSim checkpoint",
13
+ )
14
+ parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
15
+ args = parser.parse_args()
16
+
17
+ converged, atoms = relax(
18
+ bulk("Si", "diamond", a=5.43),
19
+ checkpoint=args.checkpoint,
20
+ filter="FrechetCellFilter",
21
+ fmax=0.01,
22
+ steps=20,
23
+ device=args.device,
24
+ )
25
+ print(f"Converged: {converged}")
26
+ print(f"Energy: {atoms.get_potential_energy():.6f} eV")
scripts/single_point.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+
3
+ import torch
4
+ from ase.build import bulk
5
+ from ase.units import GPa
6
+
7
+ from onescience.models.mattersim import load_calculator
8
+
9
+
10
+ def main() -> None:
11
+ parser = argparse.ArgumentParser(description="MatterSim single-point inference")
12
+ parser.add_argument("--checkpoint")
13
+ parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
14
+ args = parser.parse_args()
15
+
16
+ device = args.device or ("cuda" if torch.cuda.is_available() else "cpu")
17
+ atoms = bulk("Si", "diamond", a=5.43)
18
+ atoms.calc = load_calculator(checkpoint=args.checkpoint, device=device)
19
+
20
+ energy = atoms.get_potential_energy()
21
+ print(f"Energy (eV) = {energy}")
22
+ print(f"Energy per atom (eV/atom) = {energy / len(atoms)}")
23
+ print(f"Forces of first atom (eV/A) = {atoms.get_forces()[0]}")
24
+ stress = atoms.get_stress(voigt=False)
25
+ print(f"Stress[0][0] (eV/A^3) = {stress[0][0]}")
26
+ print(f"Stress[0][0] (GPa) = {stress[0][0] / GPa}")
27
+
28
+
29
+ if __name__ == "__main__":
30
+ main()
weight/mattersim-v1.0.0-1M.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:28b0b0b0f13efefee06b47ea4c9105a26bd3e2c8396da193430da96b3b49a8be
3
+ size 17932943