dadadaxi commited on
Commit
c25df3c
·
verified ·
1 Parent(s): ae867c4

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,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tasks:
4
+ - materials-simulation
5
+ - molecular-dynamics
6
+ - energy-prediction
7
+ - force-prediction
8
+ - structure-relaxation
9
+ - fine-tuning
10
+ frameworks:
11
+ - pytorch
12
+ language:
13
+ - en
14
+ tags:
15
+ - OneScience
16
+ - MatterSim
17
+ - materials-science
18
+ - molecular-simulation
19
+ - machine-learning-potential
20
+ - graph-neural-network
21
+ - equivariant-neural-network
22
+ - inference
23
+ - fine-tuning
24
+ ---
25
+
26
+ <p align="center">
27
+ <strong>
28
+ <span style="font-size: 30px;">MatterSim</span>
29
+ </strong>
30
+ </p>
31
+
32
+ # Model Introduction
33
+
34
+ MatterSim is a deep-learning interatomic potential developed by Microsoft Research for a broad range of elements, temperatures, and pressures. It predicts energies and forces for inorganic materials, molecules, and periodic systems.
35
+
36
+ Paper: *MatterSim: A deep-learning atomistic model across elements, temperatures, and pressures*
37
+ Reference implementation: https://github.com/microsoft/mattersim
38
+
39
+ # Model Description
40
+
41
+ MatterSim uses a deep-learning architecture trained on multiple materials and molecular datasets. It supports energy and force prediction, structure relaxation, molecular dynamics, and fine-tuning on custom datasets for inorganic materials, molecules, and periodic systems.
42
+
43
+ # Use Cases
44
+
45
+ | Use case | Description |
46
+ | :---: | :--- |
47
+ | Single-point energy/force prediction | Quickly predict the energy and atomic forces of a given atomic structure |
48
+ | Batch structure inference | Predict energies and forces for multiple structures in a batch |
49
+ | Structure relaxation | Optimize atomic positions and cell shape with FIRE/BFGS |
50
+ | Molecular dynamics | Run short MD sampling in the NVT ensemble |
51
+ | Fine-tuning on custom data | Fine-tune a pretrained MatterSim model on your own dataset |
52
+ | Environment connectivity check | Use the single-point and relaxation scripts to verify the OneScience MatChem environment, model loading, and CUDA/DCU availability |
53
+
54
+ # Usage
55
+
56
+ ## 1. Using OneCode
57
+
58
+ Try intelligent, one-click AI4S programming in the OneCode online environment:
59
+
60
+ [Try intelligent, one-click AI4S programming](https://web-2069360198568017922-iaaj.ksai.scnet.cn:58043/home)
61
+
62
+ ## 2. Manual Installation and Usage
63
+
64
+ **Hardware requirements**
65
+
66
+ - A GPU or DCU is recommended.
67
+ - A CPU can be used for import checks and small-configuration connectivity tests, but full training and inference will be slow.
68
+ - DCU users must install DTK in advance. DTK 25.04.2 or later, or the OneScience-recommended version matching the current cluster, is recommended.
69
+
70
+ ### Download the Model Package
71
+
72
+ ```bash
73
+ hf download --model OneScience-Sugon/Mattersim --local-dir ./mattersim
74
+ cd mattersim
75
+ ```
76
+
77
+ ### Install the Runtime Environment
78
+
79
+ **DCU environment**
80
+
81
+ ```bash
82
+ # Activate DTK and conda first
83
+ conda create -n onescience311 python=3.11 -y
84
+ conda activate onescience311
85
+ # uv installation is also supported
86
+ pip install onescience[matchem-dcu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
87
+ ```
88
+
89
+ **GPU environment**
90
+
91
+ ```bash
92
+ # Activate conda first
93
+ conda create -n onescience311 python=3.11 -y libstdcxx-ng=12 libgcc-ng=12 gcc_linux-64=12 gxx_linux-64=12
94
+ conda activate onescience311
95
+ # uv installation is also supported
96
+ pip install onescience[matchem-gpu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
97
+ ```
98
+
99
+ ### Training Data
100
+
101
+ By default, this repository only includes the `high_level_water.xyz` sample data for quickly validating model loading, single-point inference, structure relaxation, molecular dynamics, and fine-tuning workflows. Download any additional training data separately and place it in `data/`.
102
+
103
+ ### Trained Weights
104
+
105
+ The repository includes `weight/mattersim-v1.0.0-1M.pth`. All scripts also accept a custom model weight through `--checkpoint`.
106
+
107
+ ### Inference
108
+
109
+ ```bash
110
+ cd scripts
111
+ python single_point.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth
112
+ ```
113
+
114
+ ```bash
115
+ cd scripts
116
+ python batch_inference.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth
117
+ ```
118
+
119
+ **Structure relaxation**
120
+
121
+ ```bash
122
+ cd scripts
123
+ python relax.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth --device cuda
124
+ ```
125
+
126
+ > The default checkpoint is `../weight/mattersim-v1.0.0-1M.pth`.
127
+
128
+ **Molecular dynamics**
129
+
130
+ ```bash
131
+ cd scripts
132
+ python md.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth --device cuda
133
+ ```
134
+
135
+ > This script also uses `../weight/mattersim-v1.0.0-1M.pth` by default.
136
+
137
+ ### Fine-Tuning
138
+
139
+ Edit the paths and parameters in `scripts/finetune_config.yaml`, including `train_data_path` and `checkpoint`:
140
+
141
+ ```bash
142
+ cd scripts
143
+ # Edit train_data_path, checkpoint, and other fields in finetune_config.yaml
144
+ ```
145
+
146
+ Single GPU:
147
+
148
+ ```bash
149
+ python finetune.py --config finetune_config.yaml
150
+ ```
151
+
152
+ Multi-GPU DDP:
153
+
154
+ ```bash
155
+ torchrun --nproc_per_node=4 finetune.py --config finetune_config.yaml
156
+ ```
157
+
158
+ # Official OneScience Resources
159
+
160
+ | Platform | OneScience Main Repository | Skills Repository |
161
+ | --- | --- | --- |
162
+ | Gitee | https://gitee.com/onescience-ai/onescience | https://gitee.com/onescience-ai/oneskills |
163
+ | GitHub | https://github.com/onescience-ai/OneScience | https://github.com/onescience-ai/oneskills |
164
+
165
+ ---
166
+
167
+ # Citation and License
168
+
169
+ - The MatterSim-related code comes from the MatChem examples in the OneScience project and refers to 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).
170
+ - If you use MatterSim training or inference results in research, please cite the original MatterSim paper, the relevant OneScience projects, and the datasets 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