@platforma-open/milaboratories.3d-structure-prediction.software 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +265 -0
- package/dist/artifacts/py-archive/archive.json +1 -0
- package/dist/artifacts/py-archive/docker_x64.json +1 -0
- package/dist/docker/Dockerfile-py-archive +22 -0
- package/dist/tengo/software/immunebuilder-predict.sw.json +1 -0
- package/package.json +41 -0
- package/pkg-platforma-open-milaboratories.3d-structure-prediction.software-py-archive-1.0.0.tgz +0 -0
- package/src_python/numbering.py +103 -0
- package/src_python/pdb_writer.py +137 -0
- package/src_python/requirements.txt +4 -0
- package/src_python/run_immunebuilder.py +647 -0
- package/src_python/sanitize.py +150 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
WARN Issue while reading "/home/runner/work/3d-structure-prediction/3d-structure-prediction/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
|
+
|
|
3
|
+
> @platforma-open/milaboratories.3d-structure-prediction.software@1.0.0 build /home/runner/work/3d-structure-prediction/3d-structure-prediction/software
|
|
4
|
+
> pl-pkg build
|
|
5
|
+
|
|
6
|
+
[32minfo[39m: Building docker images...
|
|
7
|
+
[32minfo[39m: Building docker image for 'py-archive'...
|
|
8
|
+
#0 building with "default" instance using docker driver
|
|
9
|
+
|
|
10
|
+
#1 [internal] load build definition from Dockerfile-py-archive
|
|
11
|
+
#1 transferring dockerfile: 539B done
|
|
12
|
+
#1 DONE 0.0s
|
|
13
|
+
|
|
14
|
+
#2 [internal] load metadata for docker.io/library/python:3.12-slim
|
|
15
|
+
#2 ...
|
|
16
|
+
|
|
17
|
+
#3 [auth] library/python:pull token for registry-1.docker.io
|
|
18
|
+
#3 DONE 0.0s
|
|
19
|
+
|
|
20
|
+
#2 [internal] load metadata for docker.io/library/python:3.12-slim
|
|
21
|
+
#2 DONE 1.0s
|
|
22
|
+
|
|
23
|
+
#4 [internal] load .dockerignore
|
|
24
|
+
#4 transferring context: 2B done
|
|
25
|
+
#4 DONE 0.0s
|
|
26
|
+
|
|
27
|
+
#5 [internal] load build context
|
|
28
|
+
#5 transferring context: 36.38kB done
|
|
29
|
+
#5 DONE 0.0s
|
|
30
|
+
|
|
31
|
+
#6 [1/6] FROM docker.io/library/python:3.12-slim@sha256:46cb7cc2877e60fbd5e21a9ae6115c30ace7a077b9f8772da879e4590c18c2e3
|
|
32
|
+
#6 resolve docker.io/library/python:3.12-slim@sha256:46cb7cc2877e60fbd5e21a9ae6115c30ace7a077b9f8772da879e4590c18c2e3 done
|
|
33
|
+
#6 sha256:4386a385d81dba9f72ed72a6fe4237755d7f5440c84b417650f38336bbc43117 1.75kB / 1.75kB done
|
|
34
|
+
#6 sha256:7bf61a5ec2a4631b240bc8cf83404e2dd37fb06a4b4bbd34b2c36906a5fb4aee 5.66kB / 5.66kB done
|
|
35
|
+
#6 sha256:3531af2bc2a9c8883754652783cf96207d53189db279c9637b7157d034de7ecd 0B / 29.78MB 0.1s
|
|
36
|
+
#6 sha256:cb8c0a9140ac107575972113eb5fd2e6c3cdddc592371a5ac31c4623dcb13d5d 0B / 1.29MB 0.1s
|
|
37
|
+
#6 sha256:4d873bcef452ab1c054b9a0f25ace04a446c558a7b925aed2fc5bc21533e0f65 0B / 12.10MB 0.1s
|
|
38
|
+
#6 sha256:46cb7cc2877e60fbd5e21a9ae6115c30ace7a077b9f8772da879e4590c18c2e3 10.37kB / 10.37kB done
|
|
39
|
+
#6 sha256:3531af2bc2a9c8883754652783cf96207d53189db279c9637b7157d034de7ecd 29.78MB / 29.78MB 0.2s done
|
|
40
|
+
#6 sha256:cb8c0a9140ac107575972113eb5fd2e6c3cdddc592371a5ac31c4623dcb13d5d 1.29MB / 1.29MB 0.2s done
|
|
41
|
+
#6 extracting sha256:3531af2bc2a9c8883754652783cf96207d53189db279c9637b7157d034de7ecd 0.1s
|
|
42
|
+
#6 sha256:3fc9d9ab5045181fbd49d1d30a2dbad144172d4c3c141f70117ddb0b918d8357 0B / 248B 0.3s
|
|
43
|
+
#6 sha256:4d873bcef452ab1c054b9a0f25ace04a446c558a7b925aed2fc5bc21533e0f65 12.10MB / 12.10MB 0.4s done
|
|
44
|
+
#6 sha256:3fc9d9ab5045181fbd49d1d30a2dbad144172d4c3c141f70117ddb0b918d8357 248B / 248B 0.5s done
|
|
45
|
+
#6 extracting sha256:3531af2bc2a9c8883754652783cf96207d53189db279c9637b7157d034de7ecd 1.2s done
|
|
46
|
+
#6 extracting sha256:cb8c0a9140ac107575972113eb5fd2e6c3cdddc592371a5ac31c4623dcb13d5d 0.1s
|
|
47
|
+
#6 extracting sha256:cb8c0a9140ac107575972113eb5fd2e6c3cdddc592371a5ac31c4623dcb13d5d 0.1s done
|
|
48
|
+
#6 extracting sha256:4d873bcef452ab1c054b9a0f25ace04a446c558a7b925aed2fc5bc21533e0f65
|
|
49
|
+
#6 extracting sha256:4d873bcef452ab1c054b9a0f25ace04a446c558a7b925aed2fc5bc21533e0f65 0.7s done
|
|
50
|
+
#6 extracting sha256:3fc9d9ab5045181fbd49d1d30a2dbad144172d4c3c141f70117ddb0b918d8357
|
|
51
|
+
#6 extracting sha256:3fc9d9ab5045181fbd49d1d30a2dbad144172d4c3c141f70117ddb0b918d8357 done
|
|
52
|
+
#6 DONE 4.7s
|
|
53
|
+
|
|
54
|
+
#7 [2/6] WORKDIR /app
|
|
55
|
+
#7 DONE 0.0s
|
|
56
|
+
|
|
57
|
+
#8 [3/6] RUN pip install --upgrade pip wheel setuptools
|
|
58
|
+
#8 1.840 Requirement already satisfied: pip in /usr/local/lib/python3.12/site-packages (25.0.1)
|
|
59
|
+
#8 1.896 Collecting pip
|
|
60
|
+
#8 1.915 Downloading pip-26.1.1-py3-none-any.whl.metadata (4.6 kB)
|
|
61
|
+
#8 1.945 Collecting wheel
|
|
62
|
+
#8 1.949 Downloading wheel-0.47.0-py3-none-any.whl.metadata (2.3 kB)
|
|
63
|
+
#8 2.087 Collecting setuptools
|
|
64
|
+
#8 2.090 Downloading setuptools-82.0.1-py3-none-any.whl.metadata (6.5 kB)
|
|
65
|
+
#8 2.128 Collecting packaging>=24.0 (from wheel)
|
|
66
|
+
#8 2.131 Downloading packaging-26.2-py3-none-any.whl.metadata (3.5 kB)
|
|
67
|
+
#8 2.143 Downloading pip-26.1.1-py3-none-any.whl (1.8 MB)
|
|
68
|
+
#8 2.160 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 158.8 MB/s eta 0:00:00
|
|
69
|
+
#8 2.164 Downloading wheel-0.47.0-py3-none-any.whl (32 kB)
|
|
70
|
+
#8 2.170 Downloading setuptools-82.0.1-py3-none-any.whl (1.0 MB)
|
|
71
|
+
#8 2.177 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.0/1.0 MB 158.9 MB/s eta 0:00:00
|
|
72
|
+
#8 2.180 Downloading packaging-26.2-py3-none-any.whl (100 kB)
|
|
73
|
+
#8 2.211 Installing collected packages: setuptools, pip, packaging, wheel
|
|
74
|
+
#8 2.820 Attempting uninstall: pip
|
|
75
|
+
#8 2.825 Found existing installation: pip 25.0.1
|
|
76
|
+
#8 2.882 Uninstalling pip-25.0.1:
|
|
77
|
+
#8 2.892 Successfully uninstalled pip-25.0.1
|
|
78
|
+
#8 4.076 Successfully installed packaging-26.2 pip-26.1.1 setuptools-82.0.1 wheel-0.47.0
|
|
79
|
+
#8 4.076 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.
|
|
80
|
+
#8 DONE 4.3s
|
|
81
|
+
|
|
82
|
+
#9 [4/6] COPY requirements.txt .
|
|
83
|
+
#9 DONE 0.0s
|
|
84
|
+
|
|
85
|
+
#10 [5/6] RUN pip install --no-cache-dir -r requirements.txt
|
|
86
|
+
#10 0.638 Collecting ImmuneBuilder==1.2 (from -r requirements.txt (line 1))
|
|
87
|
+
#10 0.678 Downloading ImmuneBuilder-1.2-py3-none-any.whl.metadata (7.7 kB)
|
|
88
|
+
#10 0.743 Collecting torch==2.7.0 (from -r requirements.txt (line 2))
|
|
89
|
+
#10 0.746 Downloading torch-2.7.0-cp312-cp312-manylinux_2_28_x86_64.whl.metadata (29 kB)
|
|
90
|
+
#10 0.790 Collecting biopython==1.85 (from -r requirements.txt (line 3))
|
|
91
|
+
#10 0.795 Downloading biopython-1.85-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (13 kB)
|
|
92
|
+
#10 0.888 Collecting openmm==8.3.1 (from -r requirements.txt (line 4))
|
|
93
|
+
#10 0.892 Downloading openmm-8.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (1.0 kB)
|
|
94
|
+
#10 1.181 Collecting numpy (from ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
95
|
+
#10 1.185 Downloading numpy-2.4.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (6.6 kB)
|
|
96
|
+
#10 1.310 Collecting scipy>=1.6 (from ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
97
|
+
#10 1.314 Downloading scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (62 kB)
|
|
98
|
+
#10 1.337 Collecting einops>=0.3 (from ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
99
|
+
#10 1.340 Downloading einops-0.8.2-py3-none-any.whl.metadata (13 kB)
|
|
100
|
+
#10 1.362 Collecting requests (from ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
101
|
+
#10 1.365 Downloading requests-2.33.1-py3-none-any.whl.metadata (4.8 kB)
|
|
102
|
+
#10 1.382 Collecting filelock (from torch==2.7.0->-r requirements.txt (line 2))
|
|
103
|
+
#10 1.388 Downloading filelock-3.29.0-py3-none-any.whl.metadata (2.0 kB)
|
|
104
|
+
#10 1.402 Collecting typing-extensions>=4.10.0 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
105
|
+
#10 1.404 Downloading typing_extensions-4.15.0-py3-none-any.whl.metadata (3.3 kB)
|
|
106
|
+
#10 1.407 Requirement already satisfied: setuptools in /usr/local/lib/python3.12/site-packages (from torch==2.7.0->-r requirements.txt (line 2)) (82.0.1)
|
|
107
|
+
#10 1.419 Collecting sympy>=1.13.3 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
108
|
+
#10 1.422 Downloading sympy-1.14.0-py3-none-any.whl.metadata (12 kB)
|
|
109
|
+
#10 1.443 Collecting networkx (from torch==2.7.0->-r requirements.txt (line 2))
|
|
110
|
+
#10 1.446 Downloading networkx-3.6.1-py3-none-any.whl.metadata (6.8 kB)
|
|
111
|
+
#10 1.462 Collecting jinja2 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
112
|
+
#10 1.466 Downloading jinja2-3.1.6-py3-none-any.whl.metadata (2.9 kB)
|
|
113
|
+
#10 1.482 Collecting fsspec (from torch==2.7.0->-r requirements.txt (line 2))
|
|
114
|
+
#10 1.485 Downloading fsspec-2026.4.0-py3-none-any.whl.metadata (10 kB)
|
|
115
|
+
#10 1.514 Collecting nvidia-cuda-nvrtc-cu12==12.6.77 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
116
|
+
#10 1.517 Downloading nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)
|
|
117
|
+
#10 1.531 Collecting nvidia-cuda-runtime-cu12==12.6.77 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
118
|
+
#10 1.534 Downloading nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.5 kB)
|
|
119
|
+
#10 1.550 Collecting nvidia-cuda-cupti-cu12==12.6.80 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
120
|
+
#10 1.554 Downloading nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.6 kB)
|
|
121
|
+
#10 1.568 Collecting nvidia-cudnn-cu12==9.5.1.17 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
122
|
+
#10 1.571 Downloading nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_x86_64.whl.metadata (1.6 kB)
|
|
123
|
+
#10 1.580 Collecting nvidia-cublas-cu12==12.6.4.1 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
124
|
+
#10 1.584 Downloading nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.5 kB)
|
|
125
|
+
#10 1.598 Collecting nvidia-cufft-cu12==11.3.0.4 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
126
|
+
#10 1.601 Downloading nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.5 kB)
|
|
127
|
+
#10 1.614 Collecting nvidia-curand-cu12==10.3.7.77 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
128
|
+
#10 1.617 Downloading nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.5 kB)
|
|
129
|
+
#10 1.631 Collecting nvidia-cusolver-cu12==11.7.1.2 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
130
|
+
#10 1.635 Downloading nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.6 kB)
|
|
131
|
+
#10 1.647 Collecting nvidia-cusparse-cu12==12.5.4.2 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
132
|
+
#10 1.650 Downloading nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.6 kB)
|
|
133
|
+
#10 1.664 Collecting nvidia-cusparselt-cu12==0.6.3 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
134
|
+
#10 1.666 Downloading nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_x86_64.whl.metadata (6.8 kB)
|
|
135
|
+
#10 1.680 Collecting nvidia-nccl-cu12==2.26.2 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
136
|
+
#10 1.685 Downloading nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (2.0 kB)
|
|
137
|
+
#10 1.700 Collecting nvidia-nvtx-cu12==12.6.77 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
138
|
+
#10 1.705 Downloading nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.6 kB)
|
|
139
|
+
#10 1.718 Collecting nvidia-nvjitlink-cu12==12.6.85 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
140
|
+
#10 1.721 Downloading nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl.metadata (1.5 kB)
|
|
141
|
+
#10 1.730 Collecting nvidia-cufile-cu12==1.11.1.6 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
142
|
+
#10 1.733 Downloading nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (1.5 kB)
|
|
143
|
+
#10 1.746 Collecting triton==3.3.0 (from torch==2.7.0->-r requirements.txt (line 2))
|
|
144
|
+
#10 1.750 Downloading triton-3.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (1.5 kB)
|
|
145
|
+
#10 1.787 Collecting mpmath<1.4,>=1.1.0 (from sympy>=1.13.3->torch==2.7.0->-r requirements.txt (line 2))
|
|
146
|
+
#10 1.791 Downloading mpmath-1.3.0-py3-none-any.whl.metadata (8.6 kB)
|
|
147
|
+
#10 1.876 Collecting MarkupSafe>=2.0 (from jinja2->torch==2.7.0->-r requirements.txt (line 2))
|
|
148
|
+
#10 1.881 Downloading markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (2.7 kB)
|
|
149
|
+
#10 2.006 Collecting charset_normalizer<4,>=2 (from requests->ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
150
|
+
#10 2.009 Downloading charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (40 kB)
|
|
151
|
+
#10 2.021 Collecting idna<4,>=2.5 (from requests->ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
152
|
+
#10 2.024 Downloading idna-3.13-py3-none-any.whl.metadata (8.0 kB)
|
|
153
|
+
#10 2.040 Collecting urllib3<3,>=1.26 (from requests->ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
154
|
+
#10 2.043 Downloading urllib3-2.6.3-py3-none-any.whl.metadata (6.9 kB)
|
|
155
|
+
#10 2.058 Collecting certifi>=2023.5.7 (from requests->ImmuneBuilder==1.2->-r requirements.txt (line 1))
|
|
156
|
+
#10 2.061 Downloading certifi-2026.4.22-py3-none-any.whl.metadata (2.5 kB)
|
|
157
|
+
#10 2.070 Downloading ImmuneBuilder-1.2-py3-none-any.whl (32 kB)
|
|
158
|
+
#10 2.073 Downloading torch-2.7.0-cp312-cp312-manylinux_2_28_x86_64.whl (865.0 MB)
|
|
159
|
+
#10 11.73 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 865.0/865.0 MB 87.0 MB/s 0:00:09
|
|
160
|
+
#10 11.73 Downloading biopython-1.85-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.3 MB)
|
|
161
|
+
#10 11.75 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.3/3.3 MB 223.5 MB/s 0:00:00
|
|
162
|
+
#10 11.83 Downloading openmm-8.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (14.0 MB)
|
|
163
|
+
#10 12.78 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.0/14.0 MB 14.5 MB/s 0:00:00
|
|
164
|
+
#10 12.79 Downloading nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (393.1 MB)
|
|
165
|
+
#10 15.98 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 393.1/393.1 MB 171.3 MB/s 0:00:03
|
|
166
|
+
#10 15.99 Downloading nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (8.9 MB)
|
|
167
|
+
#10 16.04 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.9/8.9 MB 173.9 MB/s 0:00:00
|
|
168
|
+
#10 16.04 Downloading nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl (23.7 MB)
|
|
169
|
+
#10 16.12 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 23.7/23.7 MB 307.3 MB/s 0:00:00
|
|
170
|
+
#10 16.13 Downloading nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (897 kB)
|
|
171
|
+
#10 16.13 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 897.7/897.7 kB 453.3 MB/s 0:00:00
|
|
172
|
+
#10 16.14 Downloading nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_x86_64.whl (571.0 MB)
|
|
173
|
+
#10 22.98 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 571.0/571.0 MB 91.8 MB/s 0:00:06
|
|
174
|
+
#10 22.99 Downloading nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (200.2 MB)
|
|
175
|
+
#10 25.96 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 200.2/200.2 MB 67.2 MB/s 0:00:02
|
|
176
|
+
#10 25.97 Downloading nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (1.1 MB)
|
|
177
|
+
#10 25.98 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.1/1.1 MB 60.2 MB/s 0:00:00
|
|
178
|
+
#10 25.99 Downloading nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (56.3 MB)
|
|
179
|
+
#10 26.22 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 56.3/56.3 MB 249.3 MB/s 0:00:00
|
|
180
|
+
#10 26.22 Downloading nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (158.2 MB)
|
|
181
|
+
#10 27.18 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 158.2/158.2 MB 164.5 MB/s 0:00:00
|
|
182
|
+
#10 27.19 Downloading nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (216.6 MB)
|
|
183
|
+
#10 29.27 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 216.6/216.6 MB 103.9 MB/s 0:00:02
|
|
184
|
+
#10 29.28 Downloading nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_x86_64.whl (156.8 MB)
|
|
185
|
+
#10 32.09 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 156.8/156.8 MB 55.6 MB/s 0:00:02
|
|
186
|
+
#10 32.10 Downloading nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (201.3 MB)
|
|
187
|
+
#10 33.59 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 201.3/201.3 MB 135.1 MB/s 0:00:01
|
|
188
|
+
#10 33.59 Downloading nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl (19.7 MB)
|
|
189
|
+
#10 33.75 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 19.7/19.7 MB 122.7 MB/s 0:00:00
|
|
190
|
+
#10 33.76 Downloading nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (89 kB)
|
|
191
|
+
#10 33.76 Downloading triton-3.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (156.5 MB)
|
|
192
|
+
#10 35.75 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 156.5/156.5 MB 78.9 MB/s 0:00:01
|
|
193
|
+
#10 35.75 Downloading einops-0.8.2-py3-none-any.whl (65 kB)
|
|
194
|
+
#10 35.76 Downloading scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (35.2 MB)
|
|
195
|
+
#10 35.92 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 35.2/35.2 MB 212.1 MB/s 0:00:00
|
|
196
|
+
#10 35.93 Downloading numpy-2.4.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (16.6 MB)
|
|
197
|
+
#10 36.10 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 16.6/16.6 MB 98.3 MB/s 0:00:00
|
|
198
|
+
#10 36.10 Downloading sympy-1.14.0-py3-none-any.whl (6.3 MB)
|
|
199
|
+
#10 36.11 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.3/6.3 MB 635.9 MB/s 0:00:00
|
|
200
|
+
#10 36.12 Downloading mpmath-1.3.0-py3-none-any.whl (536 kB)
|
|
201
|
+
#10 36.12 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 536.2/536.2 kB 812.1 MB/s 0:00:00
|
|
202
|
+
#10 36.12 Downloading typing_extensions-4.15.0-py3-none-any.whl (44 kB)
|
|
203
|
+
#10 36.12 Downloading filelock-3.29.0-py3-none-any.whl (39 kB)
|
|
204
|
+
#10 36.13 Downloading fsspec-2026.4.0-py3-none-any.whl (203 kB)
|
|
205
|
+
#10 36.13 Downloading jinja2-3.1.6-py3-none-any.whl (134 kB)
|
|
206
|
+
#10 36.13 Downloading markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
|
|
207
|
+
#10 36.13 Downloading networkx-3.6.1-py3-none-any.whl (2.1 MB)
|
|
208
|
+
#10 36.14 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.1/2.1 MB 632.1 MB/s 0:00:00
|
|
209
|
+
#10 36.14 Downloading requests-2.33.1-py3-none-any.whl (64 kB)
|
|
210
|
+
#10 36.15 Downloading charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (216 kB)
|
|
211
|
+
#10 36.15 Downloading idna-3.13-py3-none-any.whl (68 kB)
|
|
212
|
+
#10 36.15 Downloading urllib3-2.6.3-py3-none-any.whl (131 kB)
|
|
213
|
+
#10 36.16 Downloading certifi-2026.4.22-py3-none-any.whl (135 kB)
|
|
214
|
+
#10 38.60 Installing collected packages: nvidia-cusparselt-cu12, mpmath, urllib3, typing-extensions, triton, sympy, nvidia-nvtx-cu12, nvidia-nvjitlink-cu12, nvidia-nccl-cu12, nvidia-curand-cu12, nvidia-cufile-cu12, nvidia-cuda-runtime-cu12, nvidia-cuda-nvrtc-cu12, nvidia-cuda-cupti-cu12, nvidia-cublas-cu12, numpy, networkx, MarkupSafe, idna, fsspec, filelock, einops, charset_normalizer, certifi, scipy, requests, openmm, nvidia-cusparse-cu12, nvidia-cufft-cu12, nvidia-cudnn-cu12, jinja2, biopython, nvidia-cusolver-cu12, torch, ImmuneBuilder
|
|
215
|
+
#10 86.40
|
|
216
|
+
#10 86.40 Successfully installed ImmuneBuilder-1.2 MarkupSafe-3.0.3 biopython-1.85 certifi-2026.4.22 charset_normalizer-3.4.7 einops-0.8.2 filelock-3.29.0 fsspec-2026.4.0 idna-3.13 jinja2-3.1.6 mpmath-1.3.0 networkx-3.6.1 numpy-2.4.4 nvidia-cublas-cu12-12.6.4.1 nvidia-cuda-cupti-cu12-12.6.80 nvidia-cuda-nvrtc-cu12-12.6.77 nvidia-cuda-runtime-cu12-12.6.77 nvidia-cudnn-cu12-9.5.1.17 nvidia-cufft-cu12-11.3.0.4 nvidia-cufile-cu12-1.11.1.6 nvidia-curand-cu12-10.3.7.77 nvidia-cusolver-cu12-11.7.1.2 nvidia-cusparse-cu12-12.5.4.2 nvidia-cusparselt-cu12-0.6.3 nvidia-nccl-cu12-2.26.2 nvidia-nvjitlink-cu12-12.6.85 nvidia-nvtx-cu12-12.6.77 openmm-8.3.1 requests-2.33.1 scipy-1.17.1 sympy-1.14.0 torch-2.7.0 triton-3.3.0 typing-extensions-4.15.0 urllib3-2.6.3
|
|
217
|
+
#10 86.40 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.
|
|
218
|
+
#10 DONE 89.2s
|
|
219
|
+
|
|
220
|
+
#11 [6/6] COPY . /app
|
|
221
|
+
#11 DONE 0.0s
|
|
222
|
+
|
|
223
|
+
#12 exporting to image
|
|
224
|
+
#12 exporting layers
|
|
225
|
+
#12 exporting layers 11.9s done
|
|
226
|
+
#12 writing image sha256:a87395ddc3da5c6821dd753df4fe45af1b28236117f4a536419b511508a56421 done
|
|
227
|
+
#12 naming to containers.pl-open.science/milaboratories/pl-containers:local-image.afeb28347e52 done
|
|
228
|
+
#12 DONE 11.9s
|
|
229
|
+
[32minfo[39m: Docker image is built:
|
|
230
|
+
tag: 'containers.pl-open.science/milaboratories/pl-containers:platforma-open.milaboratories.3d-structure-prediction.software.py-archive.a87395ddc3da'
|
|
231
|
+
location file: '/home/runner/work/3d-structure-prediction/3d-structure-prediction/software/dist/artifacts/py-archive/docker_x64.json'
|
|
232
|
+
[32minfo[39m: Building package archives...
|
|
233
|
+
[32minfo[39m: Building software package 'py-archive' for platform 'linux-x64'...
|
|
234
|
+
[32minfo[39m: software archive is built:
|
|
235
|
+
archive: '/home/runner/work/3d-structure-prediction/3d-structure-prediction/software/pkg-platforma-open-milaboratories.3d-structure-prediction.software-py-archive-1.0.0.tgz'
|
|
236
|
+
location file: '/home/runner/work/3d-structure-prediction/3d-structure-prediction/software/dist/artifacts/py-archive/archive.json'
|
|
237
|
+
[32minfo[39m: Rendering entrypoint descriptors...
|
|
238
|
+
[32minfo[39m: Writing entrypoint descriptor to '/home/runner/work/3d-structure-prediction/3d-structure-prediction/software/dist/tengo/software/immunebuilder-predict.sw.json'
|
|
239
|
+
[32minfo[39m: Publishing docker images...
|
|
240
|
+
[32minfo[39m: Publishing docker image 'containers.pl-open.science/milaboratories/pl-containers:platforma-open.milaboratories.3d-structure-prediction.software.py-archive.a87395ddc3da' using alternative tag 'quay.io/milaboratories/pl-containers:platforma-open.milaboratories.3d-structure-prediction.software.py-archive.a87395ddc3da'
|
|
241
|
+
The push refers to repository [quay.io/milaboratories/pl-containers]
|
|
242
|
+
0826d8e5c196: Preparing
|
|
243
|
+
6478b4b624ed: Preparing
|
|
244
|
+
0ad03b205566: Preparing
|
|
245
|
+
153b8cd2ae3a: Preparing
|
|
246
|
+
c23e35ce0d97: Preparing
|
|
247
|
+
82f7b847f709: Preparing
|
|
248
|
+
3a9714186f75: Preparing
|
|
249
|
+
e1ed8e09cf5d: Preparing
|
|
250
|
+
6d7c150df58d: Preparing
|
|
251
|
+
82f7b847f709: Waiting
|
|
252
|
+
3a9714186f75: Waiting
|
|
253
|
+
e1ed8e09cf5d: Waiting
|
|
254
|
+
6d7c150df58d: Waiting
|
|
255
|
+
0ad03b205566: Pushed
|
|
256
|
+
0826d8e5c196: Pushed
|
|
257
|
+
82f7b847f709: Layer already exists
|
|
258
|
+
c23e35ce0d97: Pushed
|
|
259
|
+
3a9714186f75: Layer already exists
|
|
260
|
+
e1ed8e09cf5d: Layer already exists
|
|
261
|
+
153b8cd2ae3a: Pushed
|
|
262
|
+
6d7c150df58d: Pushed
|
|
263
|
+
6478b4b624ed: Pushed
|
|
264
|
+
platforma-open.milaboratories.3d-structure-prediction.software.py-archive.a87395ddc3da: digest: sha256:034516fcbde67db5b936de6447ad9707cbc3323784480b8ada7015626c9942fb size: 2207
|
|
265
|
+
[32minfo[39m: Docker image 'containers.pl-open.science/milaboratories/pl-containers:platforma-open.milaboratories.3d-structure-prediction.software.py-archive.a87395ddc3da' not exists locally but is already in remote registry. Skipping push...
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"python","platform":"linux-x64","registryURL":"https://bin.pl-open.science/","registryName":"platforma-open","remoteArtifactLocation":"software/platforma-open/milaboratories.3d-structure-prediction.software/py-archive/1.0.0.tgz","uploadPath":"software/platforma-open/milaboratories.3d-structure-prediction.software/py-archive/1.0.0.tgz"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"docker","platform":"linux-x64","remoteArtifactLocation":"containers.pl-open.science/milaboratories/pl-containers:platforma-open.milaboratories.3d-structure-prediction.software.py-archive.a87395ddc3da","entrypoint":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Auto-generated Dockerfile for Python package
|
|
2
|
+
FROM python:3.12-slim
|
|
3
|
+
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Always keep basic python packaging tools fresh to avoid CVEs even in old python versions
|
|
9
|
+
RUN pip install --upgrade pip wheel setuptools
|
|
10
|
+
|
|
11
|
+
# Install dependencies to leverage Docker cache
|
|
12
|
+
COPY requirements.txt .
|
|
13
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
14
|
+
|
|
15
|
+
# Copy package source
|
|
16
|
+
COPY . /app
|
|
17
|
+
|
|
18
|
+
# Set Python path
|
|
19
|
+
ENV PYTHONPATH=/app
|
|
20
|
+
|
|
21
|
+
# Default command (will be overridden by entrypoint)
|
|
22
|
+
CMD ["bash"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"@platforma-open/milaboratories.3d-structure-prediction.software:immunebuilder-predict","binary":{"type":"python","registry":"platforma-open","package":"software/platforma-open/milaboratories.3d-structure-prediction.software/py-archive/1.0.0.tgz","cmd":["python","{pkg}/run_immunebuilder.py"],"envVars":[],"runEnv":{"name":"@platforma-open/milaboratories.runenv-python-3:3.12.10-atls","type":"python","registry":"platforma-open","package":"software/platforma-open/milaboratories.runenv-python-3.12.10-atls/main/1.2.4-{os}-{arch}.tgz","python-version":"3.12.10","envVars":[],"binDir":"bin"},"toolset":"pip","dependencies":{"requirements":"requirements.txt"}},"docker":{"tag":"containers.pl-open.science/milaboratories/pl-containers:platforma-open.milaboratories.3d-structure-prediction.software.py-archive.a87395ddc3da","entrypoint":[],"cmd":["python","{pkg}/run_immunebuilder.py"],"pkg":"/app"}}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@platforma-open/milaboratories.3d-structure-prediction.software",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Block Software",
|
|
6
|
+
"block-software": {
|
|
7
|
+
"artifacts": {
|
|
8
|
+
"py-archive": {
|
|
9
|
+
"type": "python",
|
|
10
|
+
"registry": "platforma-open",
|
|
11
|
+
"environment": "@platforma-open/milaboratories.runenv-python-3:3.12.10-atls",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"toolset": "pip",
|
|
14
|
+
"requirements": "requirements.txt"
|
|
15
|
+
},
|
|
16
|
+
"root": "./src_python"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"entrypoints": {
|
|
20
|
+
"immunebuilder-predict": {
|
|
21
|
+
"binary": {
|
|
22
|
+
"artifact": "py-archive",
|
|
23
|
+
"cmd": [
|
|
24
|
+
"python",
|
|
25
|
+
"{pkg}/run_immunebuilder.py"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@platforma-open/milaboratories.runenv-python-3": "1.7.12",
|
|
33
|
+
"@platforma-sdk/package-builder": "3.12.0"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"do-pack": "shx rm -f *.tgz && pl-pkg build && pnpm pack && shx mv platforma-open*.tgz package.tgz",
|
|
37
|
+
"changeset": "changeset",
|
|
38
|
+
"version-packages": "changeset version",
|
|
39
|
+
"build": "pl-pkg build"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/pkg-platforma-open-milaboratories.3d-structure-prediction.software-py-archive-1.0.0.tgz
ADDED
|
Binary file
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""IMGT numbering helpers.
|
|
2
|
+
|
|
3
|
+
ImmuneBuilder runs ANARCI internally and exposes numbered residues on the
|
|
4
|
+
Antibody object. Default scheme is typically Chothia unless configured. Until
|
|
5
|
+
runtime testing confirms the scheme emitted by `antibody.numbered_sequences`,
|
|
6
|
+
we trust what comes out and record the scheme in provenance; if a Chothia
|
|
7
|
+
fallback is needed, switch to post-hoc renumbering via the `anarci` CLI here.
|
|
8
|
+
|
|
9
|
+
IMGT CDR ranges (per spec R27):
|
|
10
|
+
CDRH1: 27-38 CDRH2: 56-65 CDRH3: 105-117
|
|
11
|
+
CDRL1: 27-38 CDRL2: 56-65 CDRL3: 105-117
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
|
|
18
|
+
IMGT_CDR_RANGES: dict[str, dict[str, tuple[int, int]]] = {
|
|
19
|
+
"H": {"CDR1": (27, 38), "CDR2": (56, 65), "CDR3": (105, 117)},
|
|
20
|
+
"L": {"CDR1": (27, 38), "CDR2": (56, 65), "CDR3": (105, 117)},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class NumberedResidue:
|
|
26
|
+
chain: str # "H" or "L"
|
|
27
|
+
pos: str # IMGT position as string; may include insertion code (e.g. "111A").
|
|
28
|
+
aa: str
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def imgt_int(self) -> int:
|
|
32
|
+
digits = "".join(c for c in self.pos if c.isdigit())
|
|
33
|
+
return int(digits) if digits else 0
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def region(self) -> str:
|
|
37
|
+
ranges = IMGT_CDR_RANGES.get(self.chain, {})
|
|
38
|
+
n = self.imgt_int
|
|
39
|
+
for name, (lo, hi) in ranges.items():
|
|
40
|
+
if lo <= n <= hi:
|
|
41
|
+
return name
|
|
42
|
+
return "FR"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def extract_numbered_residues(antibody) -> list[NumberedResidue]:
|
|
46
|
+
"""Pull residue numbering out of an ImmuneBuilder Antibody.
|
|
47
|
+
|
|
48
|
+
`antibody.numbered_sequences` is {'H': [((pos, ins), aa), ...], 'L': ...}.
|
|
49
|
+
For VHH only 'H' is present. Residues are returned in N-to-C order per
|
|
50
|
+
chain, heavy first then light.
|
|
51
|
+
"""
|
|
52
|
+
out: list[NumberedResidue] = []
|
|
53
|
+
numbered = getattr(antibody, "numbered_sequences", {}) or {}
|
|
54
|
+
for chain in ("H", "L"):
|
|
55
|
+
chain_data = numbered.get(chain, [])
|
|
56
|
+
for entry in chain_data:
|
|
57
|
+
(pos, ins), aa = entry
|
|
58
|
+
pos_str = f"{pos}{ins.strip()}" if ins and ins.strip() else str(pos)
|
|
59
|
+
out.append(NumberedResidue(chain=chain, pos=pos_str, aa=aa))
|
|
60
|
+
return out
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def cdr_ranges_in_pdb_notation(chain: str) -> dict[str, tuple[str, str]]:
|
|
64
|
+
"""Return CDR ranges formatted for REMARK 99 CDR* records.
|
|
65
|
+
|
|
66
|
+
Example: {"CDR1": ("H27", "H38"), ...} for chain H.
|
|
67
|
+
"""
|
|
68
|
+
ranges = IMGT_CDR_RANGES.get(chain, {})
|
|
69
|
+
return {
|
|
70
|
+
name: (f"{chain}{lo}", f"{chain}{hi}")
|
|
71
|
+
for name, (lo, hi) in ranges.items()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def cdrh3_length(residues: list[NumberedResidue]) -> int:
|
|
76
|
+
"""Count residues in CDRH3."""
|
|
77
|
+
return sum(1 for r in residues if r.chain == "H" and r.region == "CDR3")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# IMGT 42/49/50/52 are the same four physical FR2 residues historically
|
|
81
|
+
# described as Kabat 37/44/45/47. FR2 has no insertion-prone loops, so the
|
|
82
|
+
# correspondence is canonical (Vincke et al. 2009; Mitchell & Colwell 2018).
|
|
83
|
+
VHH_HALLMARKS_IMGT: dict[int, tuple[str, ...]] = {
|
|
84
|
+
42: ("F", "Y"), # canonical VHH; conventional VH carries V
|
|
85
|
+
49: ("E",), # canonical VHH; conventional VH carries G
|
|
86
|
+
50: ("R",), # canonical VHH; conventional VH carries L
|
|
87
|
+
52: ("G",), # canonical VHH; conventional VH carries W
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def vhh_hallmarks_present(residues: list[NumberedResidue]) -> bool:
|
|
92
|
+
"""R15 — return True when the heavy chain looks like a canonical VHH.
|
|
93
|
+
|
|
94
|
+
Reads IMGT-numbered residues already extracted from the predicted Antibody
|
|
95
|
+
(no second ANARCI call). Tolerates one humanized position: True iff at
|
|
96
|
+
least 2 of the 4 hallmark positions carry a canonical VHH residue.
|
|
97
|
+
"""
|
|
98
|
+
by_pos = {r.imgt_int: r.aa for r in residues if r.chain == "H"}
|
|
99
|
+
matches = sum(
|
|
100
|
+
1 for pos, expected in VHH_HALLMARKS_IMGT.items()
|
|
101
|
+
if by_pos.get(pos) in expected
|
|
102
|
+
)
|
|
103
|
+
return matches >= 2
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""PDB writer that augments ImmuneBuilder output with REMARKs.
|
|
2
|
+
|
|
3
|
+
ImmuneBuilder writes a standard PDB. Per spec R26/R28/R29 we need to:
|
|
4
|
+
- Clamp per-atom B-factor to [0.00, 99.99] to fit PDB `%6.2f` precision.
|
|
5
|
+
- Inject a TITLE line identifying the predictor.
|
|
6
|
+
- Inject REMARK 99 PROVENANCE block (version, seed, block version, ISO date).
|
|
7
|
+
- Inject REMARK 99 CDR* records with IMGT CDR ranges.
|
|
8
|
+
|
|
9
|
+
The cleanest approach is: let ImmuneBuilder write a temp PDB, then post-
|
|
10
|
+
process the lines — injecting REMARKs after TITLE and clamping B-factors on
|
|
11
|
+
ATOM/HETATM lines in one pass.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from numbering import IMGT_CDR_RANGES, cdr_ranges_in_pdb_notation
|
|
20
|
+
|
|
21
|
+
B_FACTOR_MIN = 0.00
|
|
22
|
+
B_FACTOR_MAX = 99.99
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _iso_now() -> str:
|
|
26
|
+
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _clamp_b_factor(line: str) -> tuple[str, bool]:
|
|
30
|
+
"""Clamp B-factor column on ATOM/HETATM lines. Returns (new_line, clamped)."""
|
|
31
|
+
if not (line.startswith("ATOM") or line.startswith("HETATM")):
|
|
32
|
+
return line, False
|
|
33
|
+
if len(line) < 66:
|
|
34
|
+
return line, False
|
|
35
|
+
raw = line[60:66]
|
|
36
|
+
try:
|
|
37
|
+
value = float(raw)
|
|
38
|
+
except ValueError:
|
|
39
|
+
return line, False
|
|
40
|
+
clamped = max(B_FACTOR_MIN, min(B_FACTOR_MAX, value))
|
|
41
|
+
if clamped == value:
|
|
42
|
+
return line, False
|
|
43
|
+
return f"{line[:60]}{clamped:6.2f}{line[66:]}", True
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _cdr_remark_lines(mode: str) -> list[str]:
|
|
47
|
+
"""Emit REMARK 99 CDR* lines (IMGT ranges)."""
|
|
48
|
+
lines: list[str] = []
|
|
49
|
+
chains = ["H"] if mode == "NanoBodyBuilder2" else ["H", "L"]
|
|
50
|
+
for chain in chains:
|
|
51
|
+
for cdr_name, (lo, hi) in cdr_ranges_in_pdb_notation(chain).items():
|
|
52
|
+
# e.g. "REMARK 99 PLATFORMA CDRH1 H27-H38"
|
|
53
|
+
label = f"CDR{chain}{cdr_name[-1]}" # CDR1 → CDRH1 / CDRL1
|
|
54
|
+
lines.append(f"REMARK 99 PLATFORMA {label} {lo}-{hi}")
|
|
55
|
+
return lines
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _provenance_remark_lines(
|
|
59
|
+
*,
|
|
60
|
+
immunebuilder_version: str,
|
|
61
|
+
torch_seed: int,
|
|
62
|
+
block_version: str,
|
|
63
|
+
numbering_scheme: str,
|
|
64
|
+
) -> list[str]:
|
|
65
|
+
return [
|
|
66
|
+
"REMARK 99 PROVENANCE",
|
|
67
|
+
f"REMARK 99 PROVENANCE immunebuilder-version={immunebuilder_version}",
|
|
68
|
+
f"REMARK 99 PROVENANCE torch-seed={torch_seed}",
|
|
69
|
+
f"REMARK 99 PROVENANCE block-version={block_version}",
|
|
70
|
+
f"REMARK 99 PROVENANCE prediction-date={_iso_now()}",
|
|
71
|
+
f"REMARK 99 PROVENANCE numbering-scheme={numbering_scheme}",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _title_line(mode: str) -> str:
|
|
76
|
+
builder = "ABodyBuilder2" if mode == "ABodyBuilder2" else "NanoBodyBuilder2"
|
|
77
|
+
return f"TITLE {builder} prediction (Platforma Structure Prediction block)"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def augment_pdb(
|
|
81
|
+
source_path: Path,
|
|
82
|
+
dest_path: Path,
|
|
83
|
+
*,
|
|
84
|
+
mode: str,
|
|
85
|
+
immunebuilder_version: str,
|
|
86
|
+
torch_seed: int,
|
|
87
|
+
block_version: str,
|
|
88
|
+
numbering_scheme: str,
|
|
89
|
+
) -> dict:
|
|
90
|
+
"""Rewrite source_path → dest_path with TITLE + REMARK injections + B clamping.
|
|
91
|
+
|
|
92
|
+
Returns stats dict: {clamped_count: int, injected_remarks: int}.
|
|
93
|
+
"""
|
|
94
|
+
with open(source_path, "r") as f:
|
|
95
|
+
src_lines = [line.rstrip("\n") for line in f]
|
|
96
|
+
|
|
97
|
+
title = _title_line(mode)
|
|
98
|
+
provenance = _provenance_remark_lines(
|
|
99
|
+
immunebuilder_version=immunebuilder_version,
|
|
100
|
+
torch_seed=torch_seed,
|
|
101
|
+
block_version=block_version,
|
|
102
|
+
numbering_scheme=numbering_scheme,
|
|
103
|
+
)
|
|
104
|
+
cdr = _cdr_remark_lines(mode)
|
|
105
|
+
injected = [title, *provenance, *cdr]
|
|
106
|
+
|
|
107
|
+
out_lines: list[str] = []
|
|
108
|
+
clamped = 0
|
|
109
|
+
header_done = False
|
|
110
|
+
|
|
111
|
+
for line in src_lines:
|
|
112
|
+
# Skip any existing TITLE that ImmuneBuilder might have put down.
|
|
113
|
+
if not header_done and line.startswith("TITLE"):
|
|
114
|
+
continue
|
|
115
|
+
if not header_done and line.startswith(("ATOM", "HETATM", "MODEL")):
|
|
116
|
+
# Inject our block before the coordinate section starts.
|
|
117
|
+
out_lines.extend(injected)
|
|
118
|
+
header_done = True
|
|
119
|
+
|
|
120
|
+
new_line, was_clamped = _clamp_b_factor(line)
|
|
121
|
+
out_lines.append(new_line)
|
|
122
|
+
if was_clamped:
|
|
123
|
+
clamped += 1
|
|
124
|
+
|
|
125
|
+
# If the PDB had no ATOM/HETATM/MODEL lines at all (shouldn't happen),
|
|
126
|
+
# still emit the REMARKs so downstream parsers don't break.
|
|
127
|
+
if not header_done:
|
|
128
|
+
out_lines = injected + out_lines
|
|
129
|
+
|
|
130
|
+
with open(dest_path, "w") as f:
|
|
131
|
+
f.write("\n".join(out_lines))
|
|
132
|
+
f.write("\n")
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
"clamped_count": clamped,
|
|
136
|
+
"injected_remarks": len(injected),
|
|
137
|
+
}
|