Skip to content

Commit 70bc6d8

Browse files
authored
[r3.0] release v3.0.2 (#4589)
This patch version only contains bug fixes, enhancements, and documentation improvements. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added Sphinx-powered documentation support. - Introduced a new test suite for dipole model evaluation. - **Bug Fixes** - Enhanced error handling for GPU support in custom operations. - **Refactor** - Upgraded key dependencies to version 2.6.0 and refined tensor operations for improved clarity and performance. - Streamlined continuous integration settings, including simplified runner selection for ARM builds and enhanced error handling. - **Documentation** - Updated default environment settings and reference links to reflect current publications. - Added a new section on using the PyTorch Profiler with TensorBoard. - **Tests & Chores** - Refined test comparisons and adjusted build configurations for enhanced stability. - Added new import for `torch._dynamo` in test files. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2 parents e5eac4a + b59bc33 commit 70bc6d8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+460
-99
lines changed

Diff for: .devcontainer/download_libtorch.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ set -ev
44
SCRIPT_PATH=$(dirname $(realpath -s $0))
55
cd ${SCRIPT_PATH}/..
66

7-
wget https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.5.0%2Bcpu.zip -O ~/libtorch.zip
7+
wget https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.6.0%2Bcpu.zip -O ~/libtorch.zip
88
unzip ~/libtorch.zip

Diff for: .github/workflows/build_wheel.yml

+1-17
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,8 @@ concurrency:
1414
cancel-in-progress: true
1515

1616
jobs:
17-
determine-arm64-runner:
18-
runs-on: ubuntu-latest
19-
permissions: read-all
20-
outputs:
21-
runner: ${{ steps.set-runner.outputs.runner }}
22-
steps:
23-
- name: Determine which runner to use for ARM64 build
24-
id: set-runner
25-
run: |
26-
if [ "${{ github.repository_owner }}" == "deepmodeling" ]; then
27-
echo "runner=[\"Linux\",\"ARM64\"]" >> $GITHUB_OUTPUT
28-
else
29-
echo "runner=\"ubuntu-latest\"" >> $GITHUB_OUTPUT
30-
fi
31-
3217
build_wheels:
3318
name: Build wheels for cp${{ matrix.python }}-${{ matrix.platform_id }}
34-
needs: determine-arm64-runner
3519
runs-on: ${{ matrix.os }}
3620
strategy:
3721
fail-fast: false
@@ -65,7 +49,7 @@ jobs:
6549
platform_id: win_amd64
6650
dp_variant: cpu
6751
# linux-aarch64
68-
- os: ${{ fromJson(needs.determine-arm64-runner.outputs.runner) }}
52+
- os: ubuntu-24.04-arm
6953
python: 310
7054
platform_id: manylinux_aarch64
7155
dp_variant: cpu

Diff for: .github/workflows/test_cc.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- run: python -m pip install uv
3030
- name: Install Python dependencies
3131
run: |
32-
source/install/uv_with_retry.sh pip install --system tensorflow-cpu
32+
source/install/uv_with_retry.sh pip install --system tensorflow-cpu~=2.18.0 jax==0.5.0
3333
export TENSORFLOW_ROOT=$(python -c 'import importlib,pathlib;print(pathlib.Path(importlib.util.find_spec("tensorflow").origin).parent)')
3434
source/install/uv_with_retry.sh pip install --system -e .[cpu,test,lmp,jax] mpi4py
3535
- name: Convert models

Diff for: .github/workflows/test_cuda.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ jobs:
4747
&& sudo apt-get -y install cuda-12-3 libcudnn8=8.9.5.*-1+cuda12.3
4848
if: false # skip as we use nvidia image
4949
- run: python -m pip install -U uv
50-
- run: source/install/uv_with_retry.sh pip install --system "tensorflow~=2.18.0rc2" "torch~=2.5.0" "jax[cuda12]"
50+
- run: source/install/uv_with_retry.sh pip install --system "tensorflow~=2.18.0rc2" "torch~=2.6.0" "jax[cuda12]==0.5.0"
5151
- run: |
5252
export PYTORCH_ROOT=$(python -c 'import torch;print(torch.__path__[0])')
5353
export TENSORFLOW_ROOT=$(python -c 'import importlib,pathlib;print(pathlib.Path(importlib.util.find_spec("tensorflow").origin).parent)')
54-
source/install/uv_with_retry.sh pip install --system -v -e .[gpu,test,lmp,cu12,torch,jax] mpi4py
54+
source/install/uv_with_retry.sh pip install --system -v -e .[gpu,test,lmp,cu12,torch,jax] mpi4py --reinstall-package deepmd-kit
5555
env:
5656
DP_VARIANT: cuda
5757
DP_ENABLE_NATIVE_OPTIMIZATION: 1
@@ -67,7 +67,7 @@ jobs:
6767
run: source/tests/infer/convert-models.sh
6868
- name: Download libtorch
6969
run: |
70-
wget https://download.pytorch.org/libtorch/cu124/libtorch-cxx11-abi-shared-with-deps-2.5.0%2Bcu124.zip -O libtorch.zip
70+
wget https://download.pytorch.org/libtorch/cu124/libtorch-cxx11-abi-shared-with-deps-2.6.0%2Bcu124.zip -O libtorch.zip
7171
unzip libtorch.zip
7272
- run: |
7373
export CMAKE_PREFIX_PATH=$GITHUB_WORKSPACE/libtorch

Diff for: .github/workflows/test_python.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ jobs:
2525
python-version: ${{ matrix.python }}
2626
- run: python -m pip install -U uv
2727
- run: |
28-
source/install/uv_with_retry.sh pip install --system openmpi tensorflow-cpu
28+
source/install/uv_with_retry.sh pip install --system openmpi tensorflow-cpu~=2.18.0
2929
source/install/uv_with_retry.sh pip install --system torch -i https://download.pytorch.org/whl/cpu
3030
export TENSORFLOW_ROOT=$(python -c 'import tensorflow;print(tensorflow.__path__[0])')
3131
export PYTORCH_ROOT=$(python -c 'import torch;print(torch.__path__[0])')
32-
source/install/uv_with_retry.sh pip install --system -e .[test,jax] mpi4py
32+
source/install/uv_with_retry.sh pip install --system -e .[test,jax] mpi4py "jax==0.5.0;python_version>='3.10'"
3333
source/install/uv_with_retry.sh pip install --system horovod --no-build-isolation
3434
env:
3535
# Please note that uv has some issues with finding

Diff for: .readthedocs.yml

+2
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ build:
1010
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH uv pip install -r doc/requirements.txt
1111
apt_packages:
1212
- inkscape
13+
sphinx:
14+
configuration: doc/conf.py
1315
formats:
1416
- pdf

Diff for: CITATIONS.bib

+25
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,31 @@ @article{Zeng_JChemPhys_2023_v159_p054801
4040
doi = {10.1063/5.0155600},
4141
}
4242

43+
@article{Zeng_arXiv_2025_p2502.19161,
44+
annote = {general purpose},
45+
author = {
46+
Jinzhe Zeng and Duo Zhang and Anyang Peng and Xiangyu Zhang and Sensen He
47+
and Yan Wang and Xinzijian Liu and Hangrui Bi and Yifan Li and Chun Cai and
48+
Chengqian Zhang and Yiming Du and Jia-Xin Zhu and Pinghui Mo and Zhengtao
49+
Huang and Qiyu Zeng and Shaochen Shi and Xuejian Qin and Zhaoxi Yu and
50+
Chenxing Luo and Ye Ding and Yun-Pei Liu and Ruosong Shi and Zhenyu Wang
51+
and Sigbj{\o}rn L{\o}land Bore and Junhan Chang and Zhe Deng and Zhaohan
52+
Ding and Siyuan Han and Wanrun Jiang and Guolin Ke and Zhaoqing Liu and
53+
Denghui Lu and Koki Muraoka and Hananeh Oliaei and Anurag Kumar Singh and
54+
Haohui Que and Weihong Xu and Zhangmancang Xu and Yong-Bin Zhuang and Jiayu
55+
Dai and Timothy J. Giese and Weile Jia and Ben Xu and Darrin M. York and
56+
Linfeng Zhang and Han Wang
57+
},
58+
title = {
59+
{DeePMD-kit v3: A Multiple-Backend Framework for Machine Learning
60+
Potentials}
61+
},
62+
journal = {arXiv},
63+
year = 2025,
64+
pages = {2502.19161},
65+
doi = {10.48550/arXiv.2502.19161},
66+
}
67+
4368
@article{Lu_CompPhysCommun_2021_v259_p107624,
4469
annote = {GPU support},
4570
title = {

Diff for: README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ If you use this code in any future publications, please cite the following publi
3636
- Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang. "DeePMD-kit v2: A software package for deep potential models." J. Chem. Phys. 159 (2023): 054801.
3737
[![doi:10.1063/5.0155600](https://img.shields.io/badge/DOI-10.1063%2F5.0155600-blue)](https://doi.org/10.1063/5.0155600)
3838
[![Citations](https://citations.njzjz.win/10.1063/5.0155600)](https://badge.dimensions.ai/details/doi/10.1063/5.0155600)
39+
- Jinzhe Zeng, Duo Zhang, Anyang Peng, Xiangyu Zhang, Sensen He, Yan Wang, Xinzijian Liu, Hangrui Bi, Yifan Li, Chun Cai, Chengqian Zhang, Yiming Du, Jia-Xin Zhu, Pinghui Mo, Zhengtao Huang, Qiyu Zeng, Shaochen Shi, Xuejian Qin, Zhaoxi Yu, Chenxing Luo, Ye Ding, Yun-Pei Liu, Ruosong Shi, Zhenyu Wang, Sigbjørn Løland Bore, Junhan Chang, Zhe Deng, Zhaohan Ding, Siyuan Han, Wanrun Jiang, Guolin Ke, Zhaoqing Liu, Denghui Lu, Koki Muraoka, Hananeh Oliaei, Anurag Kumar Singh, Haohui Que, Weihong Xu, Zhangmancang Xu, Yong-Bin Zhuang, Jiayu Dai, Timothy J. Giese, Weile Jia, Ben Xu, Darrin M. York, Linfeng Zhang, Han Wang. "DeePMD-kit v3: A Multiple-Backend Framework for Machine Learning Potentials." [arXiv:2502.19161](https://arxiv.org/abs/2502.19161).
3940

4041
In addition, please follow [the bib file](CITATIONS.bib) to cite the methods you used.
4142

@@ -68,14 +69,16 @@ In addition to building up potential energy models, DeePMD-kit can also be used
6869
- Non-von-Neumann.
6970
- C API to interface with the third-party packages.
7071

71-
See [our latest paper](https://doi.org/10.1063/5.0155600) for details of all features until v2.2.3.
72+
See [our v2 paper](https://doi.org/10.1063/5.0155600) for details of all features until v2.2.3.
7273

7374
#### v3
7475

7576
- Multiple backends supported. Add PyTorch and JAX backends.
7677
- The DPA-2 model.
7778
- Plugin mechanisms for external models.
7879

80+
See [our v3 paper](https://doi.org/10.48550/arXiv.2502.19161) for details of all features until v3.0.
81+
7982
## Install and use DeePMD-kit
8083

8184
Please read the [online documentation](https://deepmd.readthedocs.io/) for how to install and use DeePMD-kit.

Diff for: backend/find_pytorch.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def get_pt_requirement(pt_version: str = "") -> dict:
116116
cuda_version = os.environ.get("CUDA_VERSION", "12.2")
117117
if cuda_version == "" or cuda_version in SpecifierSet(">=12,<13"):
118118
# CUDA 12.2, cudnn 9
119-
pt_version = "2.5.0"
119+
pt_version = "2.6.0"
120120
elif cuda_version in SpecifierSet(">=11,<12"):
121121
# CUDA 11.8, cudnn 8
122122
pt_version = "2.3.1"

Diff for: deepmd/dpmodel/descriptor/dpa1.py

+1
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@ def call(
899899
exclude_mask = self.emask.build_type_exclude_mask(nlist, atype_ext)
900900
# nfnl x nnei
901901
exclude_mask = xp.reshape(exclude_mask, (nf * nloc, nnei))
902+
exclude_mask = xp.astype(exclude_mask, xp.bool)
902903
# nfnl x nnei
903904
nlist = xp.reshape(nlist, (nf * nloc, nnei))
904905
nlist = xp.where(exclude_mask, nlist, xp.full_like(nlist, -1))

Diff for: deepmd/dpmodel/descriptor/repformers.py

+1
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ def call(
393393
):
394394
xp = array_api_compat.array_namespace(nlist, coord_ext, atype_ext)
395395
exclude_mask = self.emask.build_type_exclude_mask(nlist, atype_ext)
396+
exclude_mask = xp.astype(exclude_mask, xp.bool)
396397
nlist = xp.where(exclude_mask, nlist, xp.full_like(nlist, -1))
397398
# nf x nloc x nnei x 4
398399
dmatrix, diff, sw = self.env_mat.call(

Diff for: deepmd/dpmodel/descriptor/se_t_tebd.py

+1
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ def call(
682682
exclude_mask = xp.reshape(exclude_mask, (nf * nloc, nnei))
683683
# nfnl x nnei
684684
nlist = xp.reshape(nlist, (nf * nloc, nnei))
685+
exclude_mask = xp.astype(exclude_mask, xp.bool)
685686
nlist = xp.where(exclude_mask, nlist, xp.full_like(nlist, -1))
686687
# nfnl x nnei
687688
nlist_mask = nlist != -1

Diff for: deepmd/dpmodel/fitting/general_fitting.py

+1
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ def _call_common(
455455
)
456456
# nf x nloc
457457
exclude_mask = self.emask.build_type_exclude_mask(atype)
458+
exclude_mask = xp.astype(exclude_mask, xp.bool)
458459
# nf x nloc x nod
459460
outs = xp.where(exclude_mask[:, :, None], outs, xp.zeros_like(outs))
460461
return {self.var_name: outs}

Diff for: deepmd/dpmodel/utils/serialization.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ def save_dp_model(filename: str, model_dict: dict) -> None:
113113
"@version": 1,
114114
"dtype": x.dtype.name,
115115
"value": x.tolist(),
116-
},
116+
}
117+
if isinstance(x, np.ndarray)
118+
else x,
117119
)
118120
with open(filename, "w") as f:
119121
yaml.safe_dump(

Diff for: deepmd/pt/model/atomic_model/dp_atomic_model.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def __init__(
6969
def set_eval_descriptor_hook(self, enable: bool) -> None:
7070
"""Set the hook for evaluating descriptor and clear the cache for descriptor list."""
7171
self.enable_eval_descriptor_hook = enable
72-
self.eval_descriptor_list = []
72+
# = [] does not work; See #4533
73+
self.eval_descriptor_list.clear()
7374

7475
def eval_descriptor(self) -> torch.Tensor:
7576
"""Evaluate the descriptor."""
@@ -236,7 +237,7 @@ def forward_atomic(
236237
)
237238
assert descriptor is not None
238239
if self.enable_eval_descriptor_hook:
239-
self.eval_descriptor_list.append(descriptor)
240+
self.eval_descriptor_list.append(descriptor.detach())
240241
# energy, force
241242
fit_ret = self.fitting_net(
242243
descriptor,

Diff for: deepmd/pt/model/descriptor/repformer_layer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,7 @@ def _cal_grrg(h2g2: torch.Tensor, axis_neuron: int) -> torch.Tensor:
10031003
# nb x nloc x 3 x ng2
10041004
nb, nloc, _, ng2 = h2g2.shape
10051005
# nb x nloc x 3 x axis
1006-
h2g2m = torch.split(h2g2, axis_neuron, dim=-1)[0]
1006+
h2g2m = h2g2[..., :axis_neuron]
10071007
# nb x nloc x axis x ng2
10081008
g1_13 = torch.matmul(torch.transpose(h2g2m, -1, -2), h2g2) / (3.0**1)
10091009
# nb x nloc x (axisxng2)

Diff for: deepmd/pt/model/network/mlp.py

+5-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import numpy as np
99
import torch
1010
import torch.nn as nn
11+
import torch.nn.functional as F
1112

1213
from deepmd.pt.utils import (
1314
env,
@@ -202,18 +203,14 @@ def forward(
202203
ori_prec = xx.dtype
203204
if not env.DP_DTYPE_PROMOTION_STRICT:
204205
xx = xx.to(self.prec)
205-
yy = (
206-
torch.matmul(xx, self.matrix) + self.bias
207-
if self.bias is not None
208-
else torch.matmul(xx, self.matrix)
209-
)
210-
yy = self.activate(yy).clone()
206+
yy = F.linear(xx, self.matrix.t(), self.bias)
207+
yy = self.activate(yy)
211208
yy = yy * self.idt if self.idt is not None else yy
212209
if self.resnet:
213210
if xx.shape[-1] == yy.shape[-1]:
214-
yy += xx
211+
yy = yy + xx
215212
elif 2 * xx.shape[-1] == yy.shape[-1]:
216-
yy += torch.concat([xx, xx], dim=-1)
213+
yy = yy + torch.concat([xx, xx], dim=-1)
217214
else:
218215
yy = yy
219216
if not env.DP_DTYPE_PROMOTION_STRICT:

Diff for: deepmd/pt/train/training.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -1230,13 +1230,11 @@ def get_loss(loss_params, start_lr, _ntypes, _model):
12301230
if "mask" in model_output_type:
12311231
model_output_type.pop(model_output_type.index("mask"))
12321232
tensor_name = model_output_type[0]
1233-
loss_params["tensor_name"] = tensor_name
12341233
loss_params["tensor_size"] = _model.model_output_def()[tensor_name].output_size
1235-
label_name = tensor_name
1236-
if label_name == "polarizability":
1237-
label_name = "polar"
1238-
loss_params["label_name"] = label_name
1239-
loss_params["tensor_name"] = label_name
1234+
loss_params["label_name"] = tensor_name
1235+
if tensor_name == "polarizability":
1236+
tensor_name = "polar"
1237+
loss_params["tensor_name"] = tensor_name
12401238
return TensorLoss(**loss_params)
12411239
elif loss_type == "property":
12421240
task_dim = _model.get_task_dim()

Diff for: deepmd/pt/utils/env.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
ncpus = len(os.sched_getaffinity(0))
2222
except AttributeError:
2323
ncpus = os.cpu_count()
24-
NUM_WORKERS = int(os.environ.get("NUM_WORKERS", min(8, ncpus)))
24+
NUM_WORKERS = int(os.environ.get("NUM_WORKERS", min(4, ncpus)))
2525
# Make sure DDP uses correct device if applicable
2626
LOCAL_RANK = os.environ.get("LOCAL_RANK")
2727
LOCAL_RANK = int(0 if LOCAL_RANK is None else LOCAL_RANK)

Diff for: deepmd/pt/utils/nlist.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ def nlist_distinguish_types(
310310
inlist = torch.gather(nlist, 2, imap)
311311
inlist = inlist.masked_fill(~(pick_mask.to(torch.bool)), -1)
312312
# nloc x nsel[ii]
313-
ret_nlist.append(torch.split(inlist, [ss, snsel - ss], dim=-1)[0])
313+
ret_nlist.append(inlist[..., :ss])
314314
return torch.concat(ret_nlist, dim=-1)
315315

316316

Diff for: deepmd/pt/utils/stat.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,9 @@ def compute_output_stats_global(
469469
# subtract the model bias and output the delta bias
470470

471471
stats_input = {
472-
kk: merged_output[kk] - model_pred[kk] for kk in keys if kk in merged_output
472+
kk: merged_output[kk] - model_pred[kk].reshape(merged_output[kk].shape)
473+
for kk in keys
474+
if kk in merged_output
473475
}
474476

475477
bias_atom_e = {}

Diff for: deepmd/tf/descriptor/descriptor.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ def get_dim_rot_mat_1(self) -> int:
105105
int
106106
the first dimension of the rotation matrix
107107
"""
108-
raise NotImplementedError
108+
# by default, no rotation matrix
109+
return 0
109110

110111
def get_nlist(self) -> tuple[tf.Tensor, tf.Tensor, list[int], list[int]]:
111112
"""Returns neighbor information.
@@ -534,3 +535,9 @@ def serialize(self, suffix: str = "") -> dict:
534535
def input_requirement(self) -> list[DataRequirementItem]:
535536
"""Return data requirements needed for the model input."""
536537
return []
538+
539+
def get_rot_mat(self) -> tf.Tensor:
540+
"""Get rotational matrix."""
541+
nframes = tf.shape(self.dout)[0]
542+
natoms = tf.shape(self.dout)[1]
543+
return tf.zeros([nframes, natoms, 0], dtype=GLOBAL_TF_FLOAT_PRECISION)

Diff for: deepmd/tf/descriptor/hybrid.py

+18
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,21 @@ def deserialize(cls, data: dict, suffix: str = "") -> "DescrptHybrid":
492492
if hasattr(ii, "type_embedding"):
493493
raise NotImplementedError("hybrid + type embedding is not supported")
494494
return obj
495+
496+
def get_dim_rot_mat_1(self) -> int:
497+
"""Returns the first dimension of the rotation matrix. The rotation is of shape
498+
dim_1 x 3.
499+
500+
Returns
501+
-------
502+
int
503+
the first dimension of the rotation matrix
504+
"""
505+
return sum([ii.get_dim_rot_mat_1() for ii in self.descrpt_list])
506+
507+
def get_rot_mat(self) -> tf.Tensor:
508+
"""Get rotational matrix."""
509+
all_rot_mat = []
510+
for ii in self.descrpt_list:
511+
all_rot_mat.append(ii.get_rot_mat())
512+
return tf.concat(all_rot_mat, axis=2)

0 commit comments

Comments
 (0)