mirror of
https://github.com/molstar/molstar.git
synced 2026-06-04 21:34:23 +08:00
Compare commits
3256 Commits
v0.2.2
...
v3.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f12f714d2 | ||
|
|
1f67077400 | ||
|
|
d1c4cf69cb | ||
|
|
803c5eaa15 | ||
|
|
970fd5d9c3 | ||
|
|
7ccd4a1e0d | ||
|
|
eb41882c56 | ||
|
|
734851a810 | ||
|
|
6318717a15 | ||
|
|
d8498feaef | ||
|
|
bce959195a | ||
|
|
4287e09a9a | ||
|
|
fdc006f833 | ||
|
|
c704b7505c | ||
|
|
ceaf238322 | ||
|
|
b7224ce5c7 | ||
|
|
95654175fe | ||
|
|
de96244706 | ||
|
|
3104ee5742 | ||
|
|
73ac445a44 | ||
|
|
1a1d1d9d30 | ||
|
|
062aff76da | ||
|
|
7d0d24b66d | ||
|
|
6655672d11 | ||
|
|
6e573ae410 | ||
|
|
1c48c02473 | ||
|
|
78be3320ce | ||
|
|
c8018800cc | ||
|
|
bb795aca98 | ||
|
|
2cb1279f4c | ||
|
|
b876c6f618 | ||
|
|
3a7dfc055e | ||
|
|
928e521ac7 | ||
|
|
e5e9598e4b | ||
|
|
e6e1809592 | ||
|
|
812f97ddb7 | ||
|
|
c6b814b31b | ||
|
|
98566fa389 | ||
|
|
4318c89bdb | ||
|
|
b41a97ce6a | ||
|
|
862c384dc0 | ||
|
|
26cc7e94c2 | ||
|
|
c6fe6ddcba | ||
|
|
154984e74d | ||
|
|
72fcaf8321 | ||
|
|
0c14ca5888 | ||
|
|
a85ede5058 | ||
|
|
db49a16184 | ||
|
|
0704db2343 | ||
|
|
425dca4665 | ||
|
|
8d65ccabd2 | ||
|
|
cbd417ca13 | ||
|
|
1e4d1e45f9 | ||
|
|
1578211157 | ||
|
|
15932dc5df | ||
|
|
7db2205956 | ||
|
|
d87f0d236a | ||
|
|
16daca6008 | ||
|
|
a0d919c8db | ||
|
|
ffee2bf1c4 | ||
|
|
de77f6ac59 | ||
|
|
c8c2ebcd65 | ||
|
|
42796b984f | ||
|
|
746557bf52 | ||
|
|
a5020a9e96 | ||
|
|
2ebb0a35fd | ||
|
|
64aaa92d45 | ||
|
|
4baf391efe | ||
|
|
5afdcff6a5 | ||
|
|
339c397860 | ||
|
|
a58cbd31ef | ||
|
|
d232b01cf9 | ||
|
|
ec95270854 | ||
|
|
78cc0d960f | ||
|
|
b5ccdfdd53 | ||
|
|
d0c0d8e703 | ||
|
|
ebf64404be | ||
|
|
7f39cf0f37 | ||
|
|
e5dcc8e54f | ||
|
|
4592510a95 | ||
|
|
46d5442dc5 | ||
|
|
271cff4aba | ||
|
|
94fd5a97d6 | ||
|
|
28678e2f80 | ||
|
|
406307a432 | ||
|
|
56345b5096 | ||
|
|
3fcc42ee0e | ||
|
|
b903677f8a | ||
|
|
ef4b632a07 | ||
|
|
e9d485ca85 | ||
|
|
a149fa5929 | ||
|
|
bb3dde585b | ||
|
|
cd6bbeaa86 | ||
|
|
e3d24dae4b | ||
|
|
687a814a62 | ||
|
|
8f2e99dc51 | ||
|
|
568be030c3 | ||
|
|
97c3ab8b5a | ||
|
|
5db646d139 | ||
|
|
340f8f1af3 | ||
|
|
4484a4452c | ||
|
|
65b654a0a2 | ||
|
|
a8e0c13b0e | ||
|
|
41d67eb642 | ||
|
|
c76c8335d1 | ||
|
|
42528b7be5 | ||
|
|
b371f8c11c | ||
|
|
3d651b40f0 | ||
|
|
895a13fc0d | ||
|
|
c94acff82e | ||
|
|
2f9ac711d1 | ||
|
|
93b9953f6d | ||
|
|
dcaf6f8927 | ||
|
|
d96eb404e1 | ||
|
|
07322819f0 | ||
|
|
9be686686d | ||
|
|
3df539c9e1 | ||
|
|
903f06bab6 | ||
|
|
13f2810f90 | ||
|
|
ee8cae16d2 | ||
|
|
feaf6f7fd4 | ||
|
|
04775a2e44 | ||
|
|
bec9fec755 | ||
|
|
e840059a38 | ||
|
|
1bd0339dec | ||
|
|
d0eaf2f71e | ||
|
|
c7edf40afe | ||
|
|
b44962eb2f | ||
|
|
254c9efbf5 | ||
|
|
73e9aed98c | ||
|
|
6e60d9713a | ||
|
|
ef0593b1e2 | ||
|
|
7831fa8b33 | ||
|
|
c64851492c | ||
|
|
4a2e93e265 | ||
|
|
d4bb1a6e93 | ||
|
|
55de0aba69 | ||
|
|
ecfa7b5a99 | ||
|
|
bee3dc4595 | ||
|
|
787ca47825 | ||
|
|
b06c134b61 | ||
|
|
3436d03468 | ||
|
|
58df6f3b85 | ||
|
|
6fab6ce1f2 | ||
|
|
9fd95f1a11 | ||
|
|
69fe0901e2 | ||
|
|
ffaf008dce | ||
|
|
eb196a41b5 | ||
|
|
35baaaf594 | ||
|
|
0fc305aaea | ||
|
|
bf67546a61 | ||
|
|
8c417ef35c | ||
|
|
01691f3050 | ||
|
|
128abf3090 | ||
|
|
0c0e995256 | ||
|
|
4090498f92 | ||
|
|
24677d6931 | ||
|
|
80d54afdd0 | ||
|
|
908fff8041 | ||
|
|
aa1eb90f66 | ||
|
|
1d21787e7e | ||
|
|
42409a2bc7 | ||
|
|
b31302ba3a | ||
|
|
3840b0041b | ||
|
|
cc68f8311d | ||
|
|
3400c8e94a | ||
|
|
61c47c517b | ||
|
|
76674917ca | ||
|
|
b835eb8de7 | ||
|
|
2a74dfcf46 | ||
|
|
b0f447adde | ||
|
|
3f0d476e94 | ||
|
|
9423d56d36 | ||
|
|
0f03fe99d6 | ||
|
|
556d5bb003 | ||
|
|
8e3ea6943f | ||
|
|
599cfc1b1c | ||
|
|
84eccb5019 | ||
|
|
2dd07bb0e3 | ||
|
|
f404d23280 | ||
|
|
8b7333b470 | ||
|
|
b8628ccff1 | ||
|
|
7d26567d40 | ||
|
|
8f6dbf2192 | ||
|
|
db350ddfd3 | ||
|
|
c0144d826c | ||
|
|
de3e819b80 | ||
|
|
bbf96567b1 | ||
|
|
c9a3254bd6 | ||
|
|
bad6d030f1 | ||
|
|
e1ad67a059 | ||
|
|
4c30057edf | ||
|
|
53a4826274 | ||
|
|
8d3ac92989 | ||
|
|
d6eb334d12 | ||
|
|
c62f19623c | ||
|
|
77139afe7f | ||
|
|
54476ad85e | ||
|
|
6dd876232d | ||
|
|
ae2314d76c | ||
|
|
6667509745 | ||
|
|
5c871a5aae | ||
|
|
393fc99ed2 | ||
|
|
7c5dff1c8b | ||
|
|
2482ef92af | ||
|
|
db59303a84 | ||
|
|
fe700953ff | ||
|
|
047946e41c | ||
|
|
ce3f13431d | ||
|
|
df54766ab2 | ||
|
|
94233fbcd9 | ||
|
|
d044496eaa | ||
|
|
ca825d720e | ||
|
|
f833efae37 | ||
|
|
be4b787e66 | ||
|
|
950b1c179a | ||
|
|
2bd1a01afb | ||
|
|
2fe43eda2b | ||
|
|
45fc0c61af | ||
|
|
7e7993f5ba | ||
|
|
9d34dbff0f | ||
|
|
ba1b03f01b | ||
|
|
791f7ca3c8 | ||
|
|
c14d50e4ff | ||
|
|
3e9de449c8 | ||
|
|
0132c7ef5e | ||
|
|
aa2222c086 | ||
|
|
fc2765d376 | ||
|
|
9d85194082 | ||
|
|
abfcc60898 | ||
|
|
c688a83fa2 | ||
|
|
77376056b9 | ||
|
|
8efd943c2b | ||
|
|
b230655439 | ||
|
|
8ba792c4b0 | ||
|
|
fde8ca69e4 | ||
|
|
9ee1439299 | ||
|
|
195668760e | ||
|
|
bd64f1db9a | ||
|
|
38a5a857aa | ||
|
|
5e8cdfe3a7 | ||
|
|
f892917e1c | ||
|
|
738b7f4ca5 | ||
|
|
bce53d03a5 | ||
|
|
74f721ab9f | ||
|
|
f011025f16 | ||
|
|
9e44cd83fa | ||
|
|
e0e45b64ac | ||
|
|
f10b152252 | ||
|
|
23cf5c2fdd | ||
|
|
e211abd5ae | ||
|
|
7199be4d62 | ||
|
|
e1a40ded1d | ||
|
|
8999c3097d | ||
|
|
44308fa1fd | ||
|
|
f5dd2f4579 | ||
|
|
104999b7dc | ||
|
|
e5341623d3 | ||
|
|
0e9238e5ec | ||
|
|
43c292e2df | ||
|
|
fbfd1b20d8 | ||
|
|
5330df87e1 | ||
|
|
ad6b3c6fe0 | ||
|
|
b983df7eb5 | ||
|
|
add76a87d9 | ||
|
|
f9f8350d28 | ||
|
|
b71c2f365c | ||
|
|
a5443189d3 | ||
|
|
7686b61728 | ||
|
|
844c13cd35 | ||
|
|
d1c8b92fdf | ||
|
|
93d33bca80 | ||
|
|
6550e53414 | ||
|
|
96dddb0998 | ||
|
|
baa64d8109 | ||
|
|
2df145aa8f | ||
|
|
06b9c5f2de | ||
|
|
e03b689f27 | ||
|
|
e4cdcff3ee | ||
|
|
f73150d074 | ||
|
|
451dc12689 | ||
|
|
a3fb7762d8 | ||
|
|
3dfafc3202 | ||
|
|
4fcea991d3 | ||
|
|
0607ed46d1 | ||
|
|
30d6244e82 | ||
|
|
fab8c74365 | ||
|
|
1952922e4e | ||
|
|
1eb351369e | ||
|
|
701d782485 | ||
|
|
dc8457c4dc | ||
|
|
f104cd4d11 | ||
|
|
9b56a6ae65 | ||
|
|
2485ad5a2f | ||
|
|
a56716ab6a | ||
|
|
e0aaaa989e | ||
|
|
9ec0f9e736 | ||
|
|
47968eeeec | ||
|
|
9c157b70e1 | ||
|
|
6d7e4ca227 | ||
|
|
fccd08d2ec | ||
|
|
19bae202d0 | ||
|
|
4ba0ae24e4 | ||
|
|
fcf3718d75 | ||
|
|
df1dd94f1c | ||
|
|
65ba401850 | ||
|
|
a98f5e1047 | ||
|
|
e5cf97d1ea | ||
|
|
1844fc14b2 | ||
|
|
d185c0ef34 | ||
|
|
40a4211e75 | ||
|
|
daa2bbd042 | ||
|
|
ed5b4b27a8 | ||
|
|
408ccb4353 | ||
|
|
99e3cd6654 | ||
|
|
0819ace1dc | ||
|
|
987c9210bd | ||
|
|
84fb42a161 | ||
|
|
53d3480701 | ||
|
|
eb629ef337 | ||
|
|
c26111e8fb | ||
|
|
4853ff7a1a | ||
|
|
1bdebda136 | ||
|
|
fe5b847797 | ||
|
|
19ec5b226c | ||
|
|
4bb32d31dc | ||
|
|
976a469cc7 | ||
|
|
86087aa3ca | ||
|
|
c0e955d472 | ||
|
|
eca052e52e | ||
|
|
a1e05387e4 | ||
|
|
301940c8bd | ||
|
|
d96303627c | ||
|
|
051b48776e | ||
|
|
26054681d8 | ||
|
|
70fa85d7d4 | ||
|
|
5a23cd483e | ||
|
|
d759b07f1b | ||
|
|
4694da0057 | ||
|
|
f930e3dbe0 | ||
|
|
fcf45d20be | ||
|
|
ad4ba7bcf9 | ||
|
|
26644ede49 | ||
|
|
810973ff54 | ||
|
|
6ad09c60c0 | ||
|
|
dc146f5f04 | ||
|
|
e1b771bba4 | ||
|
|
e2ab3a6fd6 | ||
|
|
d1296de676 | ||
|
|
fcac1a62c6 | ||
|
|
5eafddf97a | ||
|
|
e2dcbc3d65 | ||
|
|
54a388da9c | ||
|
|
3849c341b8 | ||
|
|
31f4803c0a | ||
|
|
d6e36d4ca7 | ||
|
|
0d526fdc98 | ||
|
|
04b36170d8 | ||
|
|
db787c9ea4 | ||
|
|
e1e6f9ca48 | ||
|
|
40b5605e10 | ||
|
|
609654b689 | ||
|
|
45ef00f1d1 | ||
|
|
88380ff917 | ||
|
|
bc7bfe9788 | ||
|
|
469ca6cb41 | ||
|
|
c0be790ff1 | ||
|
|
8c1d16353e | ||
|
|
d76d475015 | ||
|
|
69024152cb | ||
|
|
4a19aedec8 | ||
|
|
df89351301 | ||
|
|
9a0c87695f | ||
|
|
a393231522 | ||
|
|
33de60d365 | ||
|
|
3cf67f7605 | ||
|
|
ffdcf798e0 | ||
|
|
397e1235e7 | ||
|
|
4e77699076 | ||
|
|
b47d046505 | ||
|
|
74aa24bfa0 | ||
|
|
30d5b0ddb1 | ||
|
|
1e35ea15eb | ||
|
|
bc998ab328 | ||
|
|
e5e245f4ee | ||
|
|
c6073b894a | ||
|
|
9b11794f22 | ||
|
|
f2b9dceaab | ||
|
|
9ccaaf6c80 | ||
|
|
ecb97e525e | ||
|
|
c36c6a6d97 | ||
|
|
60b92471f1 | ||
|
|
79e283cfbd | ||
|
|
3778dacb08 | ||
|
|
e407f7279b | ||
|
|
ea54209414 | ||
|
|
d10a36509b | ||
|
|
4af560e63a | ||
|
|
ecb8900258 | ||
|
|
7bfc1b0ebc | ||
|
|
5edae9d6f7 | ||
|
|
fe702a8c63 | ||
|
|
c8868464a5 | ||
|
|
720e65d2e6 | ||
|
|
b5123ff36a | ||
|
|
d237034e8e | ||
|
|
aab95d27e0 | ||
|
|
c68306125e | ||
|
|
3173396737 | ||
|
|
212a3eeb6c | ||
|
|
17b25354f5 | ||
|
|
9f176bd2bc | ||
|
|
4a78283ce1 | ||
|
|
81e29533dc | ||
|
|
c1a2c602a1 | ||
|
|
c436653ce9 | ||
|
|
a2b4ed7c1c | ||
|
|
83968aa408 | ||
|
|
71539cc75a | ||
|
|
881d4d2a99 | ||
|
|
ae2f2e7d0e | ||
|
|
e31f0f7660 | ||
|
|
3586207968 | ||
|
|
b575793b83 | ||
|
|
81bf653790 | ||
|
|
6186c60cd9 | ||
|
|
6ab480589a | ||
|
|
571f8187c3 | ||
|
|
d510ff00dc | ||
|
|
7a0f286fb4 | ||
|
|
fccf8d6b87 | ||
|
|
e0c08e89d0 | ||
|
|
ef9885411c | ||
|
|
7542ead360 | ||
|
|
043ab08066 | ||
|
|
ec0933d197 | ||
|
|
aef34a687d | ||
|
|
9b7192f261 | ||
|
|
18212d9ee7 | ||
|
|
8d4e0730e8 | ||
|
|
ba8e9e189f | ||
|
|
b7935de7af | ||
|
|
10ca32f9d7 | ||
|
|
bb86d83c96 | ||
|
|
907b08cc99 | ||
|
|
a07d593909 | ||
|
|
a0a3ff1969 | ||
|
|
7fac8a8f77 | ||
|
|
7266c67e32 | ||
|
|
50c8d09742 | ||
|
|
7377947975 | ||
|
|
a3c4daf30a | ||
|
|
9d7e6f1d99 | ||
|
|
9e105020e3 | ||
|
|
698f7e16bd | ||
|
|
93df548cfe | ||
|
|
a0b1593c82 | ||
|
|
fc81e08d73 | ||
|
|
5369fa5adf | ||
|
|
316a77c716 | ||
|
|
42dfa69ad7 | ||
|
|
cae4eb8b0e | ||
|
|
5514b24fdf | ||
|
|
d570bc352e | ||
|
|
8a76a3fa64 | ||
|
|
71bf4e21f5 | ||
|
|
e0d36c30d3 | ||
|
|
d653a96b25 | ||
|
|
b53debcfef | ||
|
|
d0705ac226 | ||
|
|
e01eacb3fe | ||
|
|
d4102b476b | ||
|
|
83ce17174a | ||
|
|
18023d7f26 | ||
|
|
a8541d5967 | ||
|
|
8b21818f2e | ||
|
|
0b290247dc | ||
|
|
fb5010e962 | ||
|
|
178789d327 | ||
|
|
4fae526073 | ||
|
|
05f1d8085a | ||
|
|
38bbabd742 | ||
|
|
3ab958a93c | ||
|
|
f59d589a30 | ||
|
|
11f7e54704 | ||
|
|
16ebd8266e | ||
|
|
7a796a4d3d | ||
|
|
1cbb915962 | ||
|
|
80486d58c3 | ||
|
|
81bc116c4d | ||
|
|
4249064dd1 | ||
|
|
e0a594121b | ||
|
|
028c02f50d | ||
|
|
76e97d7b59 | ||
|
|
ad1181a75b | ||
|
|
5d683462fb | ||
|
|
42422bb0ea | ||
|
|
861e5c3e97 | ||
|
|
614cffda96 | ||
|
|
2e0379d202 | ||
|
|
b5cfdcd2a3 | ||
|
|
c00de6fde0 | ||
|
|
da3a8e56f3 | ||
|
|
103d6fe775 | ||
|
|
5df55e6bf7 | ||
|
|
3b285086d4 | ||
|
|
91793bc3cc | ||
|
|
fa3828e820 | ||
|
|
31ba8212da | ||
|
|
fe27d8e134 | ||
|
|
83dcdfdc4b | ||
|
|
f9aaabc1f7 | ||
|
|
034370b44c | ||
|
|
b87666df3e | ||
|
|
c98c3228fe | ||
|
|
9419980dfc | ||
|
|
42d60420e5 | ||
|
|
5b1df333a7 | ||
|
|
0bb376706d | ||
|
|
eca7da2c72 | ||
|
|
b0bdb3ddb6 | ||
|
|
3180d7c305 | ||
|
|
2faa821c50 | ||
|
|
7f355ae501 | ||
|
|
7f79ff9ff2 | ||
|
|
02de871c59 | ||
|
|
00cb783d4c | ||
|
|
c925919ee5 | ||
|
|
324820890a | ||
|
|
2687b29d4d | ||
|
|
7084aaee1a | ||
|
|
520a2f7850 | ||
|
|
9264987817 | ||
|
|
b736ed3ea4 | ||
|
|
166d660fa7 | ||
|
|
b8249cde4d | ||
|
|
f12f5eca90 | ||
|
|
cd3798b46f | ||
|
|
0240e54737 | ||
|
|
6a735d902e | ||
|
|
57a942ecb5 | ||
|
|
f67605a398 | ||
|
|
aaafa1d5ad | ||
|
|
a1d9a77653 | ||
|
|
f2f1181af3 | ||
|
|
864befc48a | ||
|
|
73f6793bd8 | ||
|
|
87ee9d88f2 | ||
|
|
b1e245e913 | ||
|
|
78c0471f39 | ||
|
|
c57b9b9214 | ||
|
|
34f33c5bbb | ||
|
|
57da2a7ebb | ||
|
|
d45d5c0e55 | ||
|
|
42ed425e65 | ||
|
|
f752ee5094 | ||
|
|
044c796942 | ||
|
|
0aabbcfaab | ||
|
|
24274cc53b | ||
|
|
870cef2fd4 | ||
|
|
bf7b1f5bfd | ||
|
|
9c9a0312db | ||
|
|
724fa2a7cd | ||
|
|
19b36e5942 | ||
|
|
b0dd9ab026 | ||
|
|
b77f1d4dee | ||
|
|
3770fd7706 | ||
|
|
e3175c3ed1 | ||
|
|
7c5dd5b15b | ||
|
|
0872e11669 | ||
|
|
a66da4defc | ||
|
|
d4ba13a2f2 | ||
|
|
3b25e037aa | ||
|
|
189fad3d84 | ||
|
|
c3c22ee3bc | ||
|
|
8a3222005c | ||
|
|
a17da36410 | ||
|
|
80323d8122 | ||
|
|
cbd6aa0b6b | ||
|
|
3831bd9941 | ||
|
|
3d3e2c3a86 | ||
|
|
acf13fa46f | ||
|
|
bc5d796653 | ||
|
|
82dd0496c2 | ||
|
|
056742ac74 | ||
|
|
29d4cfbcca | ||
|
|
376449f7c8 | ||
|
|
bc37fad007 | ||
|
|
2e561a8de7 | ||
|
|
e6c8c69d0c | ||
|
|
d121a11e28 | ||
|
|
5484a2a72c | ||
|
|
d527609b6d | ||
|
|
e628f580a7 | ||
|
|
b662179b4d | ||
|
|
fa2b8542bf | ||
|
|
901522f500 | ||
|
|
62b63c1aa5 | ||
|
|
24b36f41da | ||
|
|
c9c890782c | ||
|
|
f2c539ebd8 | ||
|
|
feb922ca91 | ||
|
|
25127bb84b | ||
|
|
8fb01d2157 | ||
|
|
c09357ea75 | ||
|
|
9f2513dae0 | ||
|
|
11a52c0390 | ||
|
|
e955dc7e94 | ||
|
|
c8107272f6 | ||
|
|
fb08fe7545 | ||
|
|
b6f054ea28 | ||
|
|
dc7e85133c | ||
|
|
90cddf4e41 | ||
|
|
2cddbb72a6 | ||
|
|
a16faaac4e | ||
|
|
6c5224f33e | ||
|
|
77d013b775 | ||
|
|
02a466e8b9 | ||
|
|
3cb65cbe3d | ||
|
|
fe8838542c | ||
|
|
78b5c9aac4 | ||
|
|
021fa7b79b | ||
|
|
0443589b09 | ||
|
|
415288de9f | ||
|
|
ecbafb086a | ||
|
|
e5dae6c0dd | ||
|
|
16f4524bdb | ||
|
|
6b33021f43 | ||
|
|
fdf37100c2 | ||
|
|
e28674d0dc | ||
|
|
fb7456286a | ||
|
|
9d240f8928 | ||
|
|
48ef5efb21 | ||
|
|
52b2e7c144 | ||
|
|
f2d1d60f6b | ||
|
|
5a176a378a | ||
|
|
60151c2c24 | ||
|
|
a5db6350a2 | ||
|
|
0618eb18ba | ||
|
|
bffdff6aad | ||
|
|
7753a6ec56 | ||
|
|
b8aafa1d78 | ||
|
|
672875187b | ||
|
|
547d60d573 | ||
|
|
99471d2a7b | ||
|
|
45d249b71a | ||
|
|
1382edd81c | ||
|
|
89a6102f8d | ||
|
|
163929477e | ||
|
|
c10a8369e8 | ||
|
|
8fbba52de8 | ||
|
|
ca3174b2c3 | ||
|
|
b9864fba80 | ||
|
|
f8e9bc1e7f | ||
|
|
f79f1507f7 | ||
|
|
61ab205a5d | ||
|
|
2c65260a4f | ||
|
|
0597a1ef24 | ||
|
|
8d6557e51c | ||
|
|
5cff0dff3d | ||
|
|
93206e76d7 | ||
|
|
40933a8539 | ||
|
|
989800783b | ||
|
|
d83b0d2c4d | ||
|
|
5e5d5a63dc | ||
|
|
b1755604e2 | ||
|
|
e58da9b574 | ||
|
|
f5d6498601 | ||
|
|
07f351888f | ||
|
|
4588fdd5d5 | ||
|
|
c3b32baf6a | ||
|
|
b8d60cea9b | ||
|
|
25b8956712 | ||
|
|
7015309db6 | ||
|
|
aad861db37 | ||
|
|
ae7811705d | ||
|
|
7e26dac50b | ||
|
|
75f43d038c | ||
|
|
b9ba940510 | ||
|
|
35603baaaa | ||
|
|
19dc32c491 | ||
|
|
95997e6a61 | ||
|
|
03e19a2ad7 | ||
|
|
765b133369 | ||
|
|
703e729514 | ||
|
|
b0216c4ce6 | ||
|
|
6796fc1cd4 | ||
|
|
87c504f9a8 | ||
|
|
2e770cb733 | ||
|
|
9f440f68e0 | ||
|
|
40028b27ba | ||
|
|
4676ad8738 | ||
|
|
e1c7833826 | ||
|
|
dd1bca0fee | ||
|
|
c38ab2c638 | ||
|
|
459c5aa5a7 | ||
|
|
b8bf07d393 | ||
|
|
ea87ac2094 | ||
|
|
e1b830a59d | ||
|
|
41e1ac76c0 | ||
|
|
98b118fd1e | ||
|
|
5f691913e4 | ||
|
|
26e2516097 | ||
|
|
3d2e4115ed | ||
|
|
dbce1ccb3d | ||
|
|
03aa2be978 | ||
|
|
8dfc52e1ab | ||
|
|
6058179f10 | ||
|
|
ea9e25b03c | ||
|
|
d60c3ddce3 | ||
|
|
724e79bddf | ||
|
|
2de61215c4 | ||
|
|
e783d9a9f1 | ||
|
|
e9e971d4f3 | ||
|
|
96dea14cb1 | ||
|
|
04fc157340 | ||
|
|
cfc24fa99e | ||
|
|
19c1088209 | ||
|
|
ee6c2e0841 | ||
|
|
20ee659b00 | ||
|
|
b6514a4a50 | ||
|
|
07b8bdb951 | ||
|
|
afd18cabd4 | ||
|
|
1117ce05d5 | ||
|
|
fc15e952bf | ||
|
|
249e5a3e0b | ||
|
|
4bfe3f6bde | ||
|
|
75b7e0b4d9 | ||
|
|
ee4ce2fd7a | ||
|
|
db0aa12e75 | ||
|
|
6d2578d3d0 | ||
|
|
99d61f48b4 | ||
|
|
146022dc12 | ||
|
|
92730cad01 | ||
|
|
d6b68b06da | ||
|
|
b174fbf0c6 | ||
|
|
fde1557955 | ||
|
|
24a0753881 | ||
|
|
5664e1d8be | ||
|
|
4881a41256 | ||
|
|
235e41ee03 | ||
|
|
94d293a4d3 | ||
|
|
40f1ca207f | ||
|
|
926fb38c1e | ||
|
|
5a14fcabc5 | ||
|
|
560e40773f | ||
|
|
6561732f57 | ||
|
|
b45cf206fd | ||
|
|
70e07be64d | ||
|
|
f3013f0e46 | ||
|
|
2e7041bd78 | ||
|
|
5d0447c9bb | ||
|
|
9eba0b91a8 | ||
|
|
58bc6722a9 | ||
|
|
1acfed3233 | ||
|
|
8147b3aa34 | ||
|
|
b21552ff36 | ||
|
|
c683cbe962 | ||
|
|
bd270e4428 | ||
|
|
23d942d8a5 | ||
|
|
cbcd6b99d2 | ||
|
|
ee5c098a9f | ||
|
|
070a15d679 | ||
|
|
befa5174f8 | ||
|
|
d6c4366f40 | ||
|
|
181cfefa63 | ||
|
|
0e7c885961 | ||
|
|
d58e90d93f | ||
|
|
cd872b47e6 | ||
|
|
2683c5b318 | ||
|
|
c71f60a164 | ||
|
|
881cbc1947 | ||
|
|
f3e7febbd1 | ||
|
|
e68ad13031 | ||
|
|
7fbbe1e63a | ||
|
|
a5ca72af3c | ||
|
|
1ce6641eb3 | ||
|
|
5dc413ab8c | ||
|
|
50b615e86c | ||
|
|
5b4c6743e7 | ||
|
|
99a3906978 | ||
|
|
981db34736 | ||
|
|
c079a8c5a8 | ||
|
|
ad70adf6ce | ||
|
|
89110b52bd | ||
|
|
8a69f050a6 | ||
|
|
9e38a44406 | ||
|
|
3514ab23c3 | ||
|
|
b59e3c383d | ||
|
|
eeba565d78 | ||
|
|
687e54cc87 | ||
|
|
ac73939440 | ||
|
|
7a3eb8d03f | ||
|
|
3d26904e0b | ||
|
|
468e14bc35 | ||
|
|
e2dc61212e | ||
|
|
aa911ad4bc | ||
|
|
bb5494264c | ||
|
|
c0116a3baa | ||
|
|
9c7497b447 | ||
|
|
fa3a79fdeb | ||
|
|
2987240df4 | ||
|
|
17a1640da5 | ||
|
|
a86da8ee11 | ||
|
|
20e373115d | ||
|
|
531260fbc5 | ||
|
|
47a3dfcef9 | ||
|
|
c5ca51fd80 | ||
|
|
2f2e44c032 | ||
|
|
26acb37098 | ||
|
|
466308cde8 | ||
|
|
dc9af9d8b0 | ||
|
|
c17bfd65e7 | ||
|
|
6de07ab8c2 | ||
|
|
0b8aab802c | ||
|
|
13f28fbe33 | ||
|
|
2eda679966 | ||
|
|
35c778b644 | ||
|
|
96f8ba5a80 | ||
|
|
0daaa94958 | ||
|
|
e672503fda | ||
|
|
4d86c9e0ae | ||
|
|
80fbc474f6 | ||
|
|
dacdc6abfc | ||
|
|
58bc8b58de | ||
|
|
07ead670dd | ||
|
|
00fd760f71 | ||
|
|
a71186905d | ||
|
|
a7e0524d01 | ||
|
|
7d7c1241d4 | ||
|
|
1f6e928d78 | ||
|
|
9bc256bdab | ||
|
|
734096260d | ||
|
|
1b4b6f9435 | ||
|
|
54fe5c85d6 | ||
|
|
f336891bf3 | ||
|
|
d2a3c9c61f | ||
|
|
6968959fe2 | ||
|
|
7749fe5000 | ||
|
|
bf45d2df5d | ||
|
|
b2222844ae | ||
|
|
3d21f1ecc6 | ||
|
|
cde280de60 | ||
|
|
9b415ddff2 | ||
|
|
906c3ac2b6 | ||
|
|
498611d4d4 | ||
|
|
a11bc73d68 | ||
|
|
9616ae5d63 | ||
|
|
c81476d2a7 | ||
|
|
397f001352 | ||
|
|
7edf274477 | ||
|
|
3c1a26c4f5 | ||
|
|
1c695846d5 | ||
|
|
a4c6d1e0e6 | ||
|
|
e51fe83800 | ||
|
|
316076d81e | ||
|
|
4073055d8d | ||
|
|
c6e0ec1c06 | ||
|
|
49aaa48e6e | ||
|
|
0eb882883e | ||
|
|
a6c25551dd | ||
|
|
0a3f73860a | ||
|
|
1de159d65c | ||
|
|
e2c411fefe | ||
|
|
3cf1c64e12 | ||
|
|
b159752b72 | ||
|
|
0d7db59c9e | ||
|
|
a8bf90a68b | ||
|
|
96aff39272 | ||
|
|
a9ae08fc1f | ||
|
|
a24f989c01 | ||
|
|
41ff45d14c | ||
|
|
6ad80bf66b | ||
|
|
eeed48a1f7 | ||
|
|
232bc0d076 | ||
|
|
ac6b87add4 | ||
|
|
2e3bff7d48 | ||
|
|
bd223b4c39 | ||
|
|
a75dc11427 | ||
|
|
30acaffb72 | ||
|
|
2818102b8b | ||
|
|
519e5a6f92 | ||
|
|
071740e7c1 | ||
|
|
7aafb2f4c3 | ||
|
|
3c72988d77 | ||
|
|
3c01dfbd42 | ||
|
|
3a5829aa3e | ||
|
|
ffeeddb37a | ||
|
|
50945493c1 | ||
|
|
fa80c4797a | ||
|
|
650e8bf703 | ||
|
|
13d57737ae | ||
|
|
a6d1a3dfdd | ||
|
|
afffdc06e5 | ||
|
|
80f1b1c795 | ||
|
|
06111e2731 | ||
|
|
adb49371bb | ||
|
|
7b726ded20 | ||
|
|
9f85a0c840 | ||
|
|
f92755c920 | ||
|
|
d141c27765 | ||
|
|
062ac65f0f | ||
|
|
bb420d0806 | ||
|
|
0018032423 | ||
|
|
3dd48ac73c | ||
|
|
4632a6f305 | ||
|
|
eda570d4f1 | ||
|
|
b0127d746d | ||
|
|
5a66ca69c4 | ||
|
|
1c17277f03 | ||
|
|
d771bdc8ff | ||
|
|
eace3f4259 | ||
|
|
8f88da70a6 | ||
|
|
b797be9642 | ||
|
|
2395b7a10a | ||
|
|
0764795c08 | ||
|
|
ea8b7a1d56 | ||
|
|
7c6827f5f5 | ||
|
|
5a6f16ef8d | ||
|
|
8dfdcdd0b7 | ||
|
|
67a2594108 | ||
|
|
871f9635e3 | ||
|
|
25251f3546 | ||
|
|
98824f477e | ||
|
|
aae9a117e8 | ||
|
|
452639c3ce | ||
|
|
6bd45e0a9b | ||
|
|
be100a3ac6 | ||
|
|
96a8cd789c | ||
|
|
d195e1dbf5 | ||
|
|
e6a8e788f5 | ||
|
|
a755ed441e | ||
|
|
de8f294329 | ||
|
|
021171c07d | ||
|
|
013ddb72ed | ||
|
|
207c226f66 | ||
|
|
b4ff98499b | ||
|
|
8471d337a2 | ||
|
|
2f84b94227 | ||
|
|
8dcd6063b7 | ||
|
|
caefe7ba67 | ||
|
|
ad6cebc59b | ||
|
|
e8d2e6d806 | ||
|
|
39352c40d1 | ||
|
|
9994262abc | ||
|
|
5bcf923381 | ||
|
|
ab5dd0b733 | ||
|
|
5a8a6310f8 | ||
|
|
a634c7a587 | ||
|
|
353c5d6d95 | ||
|
|
92698c486c | ||
|
|
898dd1161d | ||
|
|
361f289d0e | ||
|
|
b49d036fcd | ||
|
|
cfee9d86c0 | ||
|
|
92622dfbd7 | ||
|
|
80c2876350 | ||
|
|
fb99f6db8a | ||
|
|
862f8193ef | ||
|
|
490c6679eb | ||
|
|
dd278ca964 | ||
|
|
0892bb24d0 | ||
|
|
83ce5e9422 | ||
|
|
c4ba92c7cb | ||
|
|
846bdf10b0 | ||
|
|
91a46ea7df | ||
|
|
e4ec68a86c | ||
|
|
410655052f | ||
|
|
17162e967a | ||
|
|
c119a1bc21 | ||
|
|
7f2e98f714 | ||
|
|
82f5d8be21 | ||
|
|
73fa675346 | ||
|
|
1f2812b2e3 | ||
|
|
6f05179db8 | ||
|
|
fc8848e97c | ||
|
|
b991102bfa | ||
|
|
e3768805a6 | ||
|
|
cdb65665a6 | ||
|
|
3765bc410c | ||
|
|
69bbd76f33 | ||
|
|
b61b3e1115 | ||
|
|
835f717e47 | ||
|
|
6a35a3ece0 | ||
|
|
518621a1bd | ||
|
|
51acfa1dce | ||
|
|
5be6c9176a | ||
|
|
dfa83c94f7 | ||
|
|
67aedd4770 | ||
|
|
346eb59da9 | ||
|
|
3195594ef3 | ||
|
|
489b412308 | ||
|
|
2d0e8d4ca0 | ||
|
|
27f94c81a2 | ||
|
|
1e865ecacc | ||
|
|
f293a02485 | ||
|
|
ddf00600c6 | ||
|
|
88cd639493 | ||
|
|
0a30ed45f9 | ||
|
|
b5b282c141 | ||
|
|
c4c60cb263 | ||
|
|
e3cf4e928e | ||
|
|
d8a08ef900 | ||
|
|
8b8f3bf492 | ||
|
|
3983073d6c | ||
|
|
82b22fa3f2 | ||
|
|
8a38f73771 | ||
|
|
37da82b138 | ||
|
|
dd17cb23d9 | ||
|
|
8f3afd9f7c | ||
|
|
6e39188f0b | ||
|
|
667cacea12 | ||
|
|
49f0ec981c | ||
|
|
a60d6e9223 | ||
|
|
2d111c1e25 | ||
|
|
874cde4f72 | ||
|
|
826318760e | ||
|
|
de790051aa | ||
|
|
00bf75839e | ||
|
|
b9d4501dcc | ||
|
|
46fb1789b0 | ||
|
|
a1e8bf841b | ||
|
|
6662dbfdd6 | ||
|
|
39b9710d16 | ||
|
|
4fe303da72 | ||
|
|
0662506d35 | ||
|
|
ea987f5601 | ||
|
|
bcae586122 | ||
|
|
e56f188a12 | ||
|
|
8fda9beb7b | ||
|
|
0f50a6682b | ||
|
|
524d38c450 | ||
|
|
68a2e52355 | ||
|
|
447d1f940f | ||
|
|
1cbb59b5d0 | ||
|
|
6f5bcdef90 | ||
|
|
f6f1c5a350 | ||
|
|
f6545c38be | ||
|
|
53fe73d3ee | ||
|
|
3bf5ab1ef7 | ||
|
|
b4813ff866 | ||
|
|
845269e9a5 | ||
|
|
59968d92ab | ||
|
|
d5b7cd370b | ||
|
|
b4434cce17 | ||
|
|
e73227519b | ||
|
|
f8e6d5cbfb | ||
|
|
70bde8c899 | ||
|
|
361dce2b96 | ||
|
|
c83ce28bf4 | ||
|
|
b9a3620a4c | ||
|
|
a939a57811 | ||
|
|
8388ee8f1e | ||
|
|
befa40f5a2 | ||
|
|
36257e2b0f | ||
|
|
769022e88c | ||
|
|
51c180a8f4 | ||
|
|
2ffc5dc5c0 | ||
|
|
431ba01117 | ||
|
|
c6a4350b81 | ||
|
|
9ef8d0c9f8 | ||
|
|
e7606477c2 | ||
|
|
de093b5472 | ||
|
|
88cd9184d8 | ||
|
|
055c169c1f | ||
|
|
1988275695 | ||
|
|
82451bff00 | ||
|
|
e6fd0202a6 | ||
|
|
c21d84dd62 | ||
|
|
f392ac21cd | ||
|
|
d4e5473b86 | ||
|
|
760298c6bf | ||
|
|
d949b99629 | ||
|
|
fff9719e48 | ||
|
|
5858a6eb19 | ||
|
|
46acc1b95e | ||
|
|
da4654b859 | ||
|
|
32869a9a45 | ||
|
|
4cfbccc5d6 | ||
|
|
6301196e67 | ||
|
|
0c61c2badd | ||
|
|
1207526161 | ||
|
|
405d9d524f | ||
|
|
f724717821 | ||
|
|
6247efa8b6 | ||
|
|
7045545419 | ||
|
|
17a0a2be6f | ||
|
|
0e92cfa007 | ||
|
|
04e17872d0 | ||
|
|
59255c720d | ||
|
|
eb71e2c606 | ||
|
|
db2905ba9f | ||
|
|
d097a4abd2 | ||
|
|
459cfd7ab8 | ||
|
|
317229afee | ||
|
|
1e2f16d6b3 | ||
|
|
be07c1668f | ||
|
|
90ddb3dc34 | ||
|
|
f968e86387 | ||
|
|
56639f0bda | ||
|
|
8ae40bfd7c | ||
|
|
a7901c53ce | ||
|
|
76f856fa4f | ||
|
|
63a4cda442 | ||
|
|
603aa89609 | ||
|
|
51dd388912 | ||
|
|
c4708f0260 | ||
|
|
dcfe2e3072 | ||
|
|
9d536fefff | ||
|
|
ed69d15ee1 | ||
|
|
4cd7f0575e | ||
|
|
ad1507dadf | ||
|
|
c358259437 | ||
|
|
6b961c532f | ||
|
|
bb8f872a13 | ||
|
|
93df8a65cd | ||
|
|
de9fd2fcd7 | ||
|
|
24ae8dfda8 | ||
|
|
909e4b3a9f | ||
|
|
09c46447d9 | ||
|
|
239a7cc072 | ||
|
|
f7ccff61e0 | ||
|
|
f8a7483467 | ||
|
|
0a7b3fa396 | ||
|
|
e5cf8bcc04 | ||
|
|
f93230ce44 | ||
|
|
bdde2cea31 | ||
|
|
d44bb6c908 | ||
|
|
052e30b739 | ||
|
|
48a7ac80f5 | ||
|
|
c9717c2332 | ||
|
|
aaed0a9a63 | ||
|
|
c29648ac9b | ||
|
|
cb1f52a8f4 | ||
|
|
5f759edc1b | ||
|
|
8897261836 | ||
|
|
23b1426567 | ||
|
|
329658ff54 | ||
|
|
482059cc9b | ||
|
|
4e509fc479 | ||
|
|
6b1edd9d10 | ||
|
|
d0c692fe03 | ||
|
|
36ee1089a8 | ||
|
|
723bf3e657 | ||
|
|
dc08e524b3 | ||
|
|
3ecd305adf | ||
|
|
60eb42391e | ||
|
|
26f5210518 | ||
|
|
7b41d800c0 | ||
|
|
3aa9ef7595 | ||
|
|
fad5a40ec4 | ||
|
|
58e0ba016e | ||
|
|
b8f168ebf5 | ||
|
|
560c26c73f | ||
|
|
73ada6b1f1 | ||
|
|
4f2cee3b56 | ||
|
|
ad6975c99d | ||
|
|
bea462b8b2 | ||
|
|
5652fa55db | ||
|
|
d2208a0814 | ||
|
|
62a456ce82 | ||
|
|
bef1142a31 | ||
|
|
8e07de62dc | ||
|
|
347b9ead6b | ||
|
|
6d9a09620c | ||
|
|
17349b8529 | ||
|
|
3a200fe2d7 | ||
|
|
10bd513680 | ||
|
|
9214c54e7d | ||
|
|
64da492d63 | ||
|
|
cbb65aaaac | ||
|
|
78c9dda257 | ||
|
|
20450e352f | ||
|
|
9559c22858 | ||
|
|
0d39dc69f1 | ||
|
|
1a29159dfd | ||
|
|
8c21d3b9d9 | ||
|
|
24143d7078 | ||
|
|
22ead527f2 | ||
|
|
104666a13e | ||
|
|
f9ea48fd7b | ||
|
|
80598dc102 | ||
|
|
fbaaa57ca2 | ||
|
|
b0113d6189 | ||
|
|
da1fa03a5f | ||
|
|
48d0418f0e | ||
|
|
cf0122ce23 | ||
|
|
7216a25877 | ||
|
|
89eae0807e | ||
|
|
bfc52fbc6b | ||
|
|
94cd5d3395 | ||
|
|
30d34584bf | ||
|
|
c81166d04b | ||
|
|
3384a8630b | ||
|
|
e39c7c4e98 | ||
|
|
38e838a352 | ||
|
|
cea22c0ea1 | ||
|
|
6b73361963 | ||
|
|
096a4ee63e | ||
|
|
28c8d6bef9 | ||
|
|
37fdbfe12a | ||
|
|
295cb84cc8 | ||
|
|
b5252516e3 | ||
|
|
8e2c0327d6 | ||
|
|
eaa92b75a3 | ||
|
|
ab81c89a9a | ||
|
|
e49af151c1 | ||
|
|
78ca5cbb43 | ||
|
|
48c242d59d | ||
|
|
8b4603d5a1 | ||
|
|
cc6dce8845 | ||
|
|
b2eac8092c | ||
|
|
a22362bac8 | ||
|
|
298b283686 | ||
|
|
14f4de2e3f | ||
|
|
9bde4c40b0 | ||
|
|
61390cb64f | ||
|
|
1b67bc41f5 | ||
|
|
5b698b816e | ||
|
|
bf9303ea80 | ||
|
|
017676c148 | ||
|
|
526f7700b2 | ||
|
|
220e01106f | ||
|
|
240de5b24d | ||
|
|
17a001427b | ||
|
|
a423970b9c | ||
|
|
56f4c8775f | ||
|
|
5ed4aa0fae | ||
|
|
4f4245b895 | ||
|
|
bc6d2112e2 | ||
|
|
3b2b87d264 | ||
|
|
181646f052 | ||
|
|
ea5a945810 | ||
|
|
7cfdc8ab1b | ||
|
|
52e011ade9 | ||
|
|
895e2ede2d | ||
|
|
3a25769a94 | ||
|
|
5db4b48a86 | ||
|
|
aa2899bfbd | ||
|
|
40bbd87c4e | ||
|
|
fb7dd66600 | ||
|
|
e12dc2b089 | ||
|
|
78242b18c3 | ||
|
|
9043e4c8e1 | ||
|
|
54b5e3a0cc | ||
|
|
b6719a2f57 | ||
|
|
087d5fbb68 | ||
|
|
4f60c91256 | ||
|
|
99415ef290 | ||
|
|
d446a2d047 | ||
|
|
b476f738bc | ||
|
|
4c0d1383b2 | ||
|
|
6a924bf732 | ||
|
|
5e1f1220af | ||
|
|
d13ee0a2cc | ||
|
|
826127672a | ||
|
|
df8dd7278a | ||
|
|
cbdc4a3e9d | ||
|
|
75266ad257 | ||
|
|
0e93374b2d | ||
|
|
8e350617f2 | ||
|
|
f6acf0a60a | ||
|
|
7982f25a45 | ||
|
|
ddafa7aac1 | ||
|
|
65946c3045 | ||
|
|
63d699d620 | ||
|
|
e1170c0552 | ||
|
|
97612bf044 | ||
|
|
012ac33bd5 | ||
|
|
272e208fd4 | ||
|
|
714f0623bb | ||
|
|
5327962409 | ||
|
|
7c3529ae30 | ||
|
|
61c63df9e9 | ||
|
|
9b6fcaeb79 | ||
|
|
ef3f035f27 | ||
|
|
e9bc67fbf4 | ||
|
|
745f2aecf8 | ||
|
|
eff80ad5ff | ||
|
|
27ef44b833 | ||
|
|
9d0190c11c | ||
|
|
0069687233 | ||
|
|
478033d405 | ||
|
|
58f57d5ad2 | ||
|
|
3f80230f4f | ||
|
|
da35f0ea16 | ||
|
|
72bdd5bc05 | ||
|
|
255cc620a5 | ||
|
|
4753271a6d | ||
|
|
11c7024edd | ||
|
|
47ba54199f | ||
|
|
cd7643e79b | ||
|
|
9a797e39e5 | ||
|
|
7898840003 | ||
|
|
8e91cb6d54 | ||
|
|
893401f7c4 | ||
|
|
021e6ffeb5 | ||
|
|
4080c1e005 | ||
|
|
5063e99761 | ||
|
|
a59f6546c5 | ||
|
|
3a737099ad | ||
|
|
d1f76fd48e | ||
|
|
437d52e484 | ||
|
|
610977cc08 | ||
|
|
6c78adb353 | ||
|
|
abef75bfa2 | ||
|
|
8137d4acdb | ||
|
|
899a186808 | ||
|
|
bb7d3e075c | ||
|
|
78ba9df263 | ||
|
|
9126416389 | ||
|
|
eef944b617 | ||
|
|
208cc2e48e | ||
|
|
1522bf4ae4 | ||
|
|
422f4567f1 | ||
|
|
6c8ae32ff9 | ||
|
|
e67c610b84 | ||
|
|
96aa003702 | ||
|
|
f6262f4be5 | ||
|
|
efc5bf6a45 | ||
|
|
cbc9801477 | ||
|
|
94e21e8a3a | ||
|
|
2ed118604c | ||
|
|
219d4f4d33 | ||
|
|
a937e3c57d | ||
|
|
9fe16e321e | ||
|
|
697e9986b4 | ||
|
|
613cdc3145 | ||
|
|
a2bf489017 | ||
|
|
aca49b9ba5 | ||
|
|
11d5e301f3 | ||
|
|
2797b451fb | ||
|
|
e82918db6a | ||
|
|
e0b98f70f0 | ||
|
|
297b9bd3ff | ||
|
|
013a59857d | ||
|
|
0b14381255 | ||
|
|
e1e0b0f2da | ||
|
|
2142290300 | ||
|
|
aeb7c7033d | ||
|
|
0f8540e7fc | ||
|
|
f14b57fe30 | ||
|
|
abfb1d5992 | ||
|
|
35c53b27fe | ||
|
|
a7f144e810 | ||
|
|
f4cb3aeed7 | ||
|
|
bceb044552 | ||
|
|
5e41e959f8 | ||
|
|
c95d54f9cd | ||
|
|
8149a25ad4 | ||
|
|
d500393501 | ||
|
|
9d2fa3e749 | ||
|
|
ee886244fc | ||
|
|
f2557fe80a | ||
|
|
bf904a5b32 | ||
|
|
76a5ce8f14 | ||
|
|
1ff83d9648 | ||
|
|
d121ed8b6c | ||
|
|
6c27deed74 | ||
|
|
7e2d15f329 | ||
|
|
10bd7853f3 | ||
|
|
4a7bfe953c | ||
|
|
3598d13a3d | ||
|
|
96ac561279 | ||
|
|
2c81267ca7 | ||
|
|
395fa5dad1 | ||
|
|
d15340e62e | ||
|
|
eab4c08836 | ||
|
|
69c5bf0094 | ||
|
|
6c112f83e8 | ||
|
|
f49c34c551 | ||
|
|
3ab4458cb2 | ||
|
|
ad3c07c634 | ||
|
|
68525c2109 | ||
|
|
9e9851472d | ||
|
|
c0edb27323 | ||
|
|
0a70783b5e | ||
|
|
a3d101cdf9 | ||
|
|
7255e08ecf | ||
|
|
b1bdb8e66b | ||
|
|
49c8c7f396 | ||
|
|
d3b4280589 | ||
|
|
bb9acaaa9c | ||
|
|
fc10b9bf7b | ||
|
|
5fcb495d24 | ||
|
|
b2fdcba674 | ||
|
|
0d01948ba9 | ||
|
|
c4370670cb | ||
|
|
1b19136c18 | ||
|
|
217e983da8 | ||
|
|
57338bdad1 | ||
|
|
0e84bf9513 | ||
|
|
0be28cacdf | ||
|
|
017c608439 | ||
|
|
20ee9496e3 | ||
|
|
6fd81d0961 | ||
|
|
823a68f9bf | ||
|
|
deab18e805 | ||
|
|
19016b6730 | ||
|
|
4319ae251c | ||
|
|
e5920e29b4 | ||
|
|
c376ddfc9d | ||
|
|
8fe2d3f724 | ||
|
|
4d7a128528 | ||
|
|
663ec9695e | ||
|
|
5e6eb7ed49 | ||
|
|
dfaa4dacdb | ||
|
|
f7adb8b589 | ||
|
|
cb6b1bf19d | ||
|
|
27a4e1d7d9 | ||
|
|
0cba88ad8c | ||
|
|
e535c4efa8 | ||
|
|
31f58ee110 | ||
|
|
2a9f6c88a0 | ||
|
|
feb167dcf8 | ||
|
|
1b53ea846b | ||
|
|
88b9be5fd1 | ||
|
|
89486ea9e2 | ||
|
|
86c09ead98 | ||
|
|
1f60d887a8 | ||
|
|
a672115505 | ||
|
|
8f54ea137d | ||
|
|
4171008c3f | ||
|
|
3a9c3780ac | ||
|
|
fe55f33bd1 | ||
|
|
71bc88c041 | ||
|
|
a5aadfef0e | ||
|
|
0b368ef804 | ||
|
|
f398993d33 | ||
|
|
b6f59ca9c3 | ||
|
|
c857c17bb4 | ||
|
|
3415fe0847 | ||
|
|
1569958a29 | ||
|
|
3543faa0c2 | ||
|
|
251dbf3877 | ||
|
|
32d35efef0 | ||
|
|
8b6428a61d | ||
|
|
dda43370cf | ||
|
|
92c1e979c0 | ||
|
|
ad38a33943 | ||
|
|
88c276a4c7 | ||
|
|
0a3d19235d | ||
|
|
0d90fd1f06 | ||
|
|
02d3274e83 | ||
|
|
2531af2b94 | ||
|
|
850328be4e | ||
|
|
f8ce9cbb65 | ||
|
|
2af9d1cabf | ||
|
|
e8d1737d40 | ||
|
|
0328e93518 | ||
|
|
8a4ab9bdb9 | ||
|
|
410cdb193d | ||
|
|
a278337b4c | ||
|
|
b1308de0b9 | ||
|
|
9705078970 | ||
|
|
b1ca98e945 | ||
|
|
35054eaca9 | ||
|
|
2747c743c9 | ||
|
|
031d08a8d4 | ||
|
|
7cc6c4a9c8 | ||
|
|
ff27098514 | ||
|
|
545cd65066 | ||
|
|
84bfc6e7a9 | ||
|
|
2f71c4c5e4 | ||
|
|
1448f7aeb6 | ||
|
|
79d66a5cfc | ||
|
|
2ec19ac04c | ||
|
|
f62a6d4512 | ||
|
|
4fbcee3953 | ||
|
|
12bb283b97 | ||
|
|
13d776c7cb | ||
|
|
f45b48c6e1 | ||
|
|
ff14c94a90 | ||
|
|
0a0ef35b74 | ||
|
|
e3dc10c085 | ||
|
|
46113bf3d4 | ||
|
|
0f3ef61f7d | ||
|
|
86aae08257 | ||
|
|
06bf2c39a1 | ||
|
|
66a23bc2a2 | ||
|
|
51e86f1e43 | ||
|
|
78c70b3f5b | ||
|
|
8f52ffe061 | ||
|
|
e95b91ab84 | ||
|
|
f4dbd66496 | ||
|
|
5895df0499 | ||
|
|
6d0d88f3be | ||
|
|
7e71428cc3 | ||
|
|
2e215440f7 | ||
|
|
c04fa56c6c | ||
|
|
6c70b5e38f | ||
|
|
ad9160a4a3 | ||
|
|
c747d3928e | ||
|
|
68e8d67054 | ||
|
|
9e8fc76d28 | ||
|
|
d8970305de | ||
|
|
824675a658 | ||
|
|
090ad613cc | ||
|
|
ea35e09c96 | ||
|
|
d8b9a1a560 | ||
|
|
c259f58e63 | ||
|
|
9d4c2a1147 | ||
|
|
f13c3fe38b | ||
|
|
60409df145 | ||
|
|
1d7321cd6f | ||
|
|
eb68ccbf6b | ||
|
|
b1ece44c49 | ||
|
|
37ae274fb6 | ||
|
|
c900045fcd | ||
|
|
50d95ccf6a | ||
|
|
c9171444eb | ||
|
|
56ea62af71 | ||
|
|
9e81626928 | ||
|
|
84fda6e35d | ||
|
|
0f758cf554 | ||
|
|
a6605052db | ||
|
|
8514175da2 | ||
|
|
6a49427fc0 | ||
|
|
7c18e5eb86 | ||
|
|
2a7d258715 | ||
|
|
54fb9beeee | ||
|
|
27ebbc50d5 | ||
|
|
2a1b6e52b2 | ||
|
|
3110e82d92 | ||
|
|
4be999ce32 | ||
|
|
f0d7a4ed2a | ||
|
|
2dacfcb485 | ||
|
|
6218cc5371 | ||
|
|
b4808f2909 | ||
|
|
1a2e9eaa84 | ||
|
|
056ce42097 | ||
|
|
b14b5ca626 | ||
|
|
ffbaa944f2 | ||
|
|
e2ba96174a | ||
|
|
8c5d99bb54 | ||
|
|
b18b3be070 | ||
|
|
2e69b7c419 | ||
|
|
5007f5fb72 | ||
|
|
6fe83a9a70 | ||
|
|
20af084127 | ||
|
|
d6501170e6 | ||
|
|
5f33364514 | ||
|
|
7924c008fa | ||
|
|
2d2a53f28e | ||
|
|
1f7ffabef9 | ||
|
|
16d5c07224 | ||
|
|
2392bfb579 | ||
|
|
b4036f576c | ||
|
|
7e3cca5780 | ||
|
|
690d6812dc | ||
|
|
a44aa02f13 | ||
|
|
65ddd6d68a | ||
|
|
754025b3b1 | ||
|
|
f0649c5aa3 | ||
|
|
6df045211c | ||
|
|
0b9371527e | ||
|
|
8a00540de0 | ||
|
|
0d78905686 | ||
|
|
6edab203c2 | ||
|
|
0abfdb5ee3 | ||
|
|
88369158c9 | ||
|
|
8926575283 | ||
|
|
15b0288ce4 | ||
|
|
28853ec19d | ||
|
|
e3480a076a | ||
|
|
abf6452124 | ||
|
|
2cdd811dd3 | ||
|
|
be6fea39bf | ||
|
|
ed1bc2cd07 | ||
|
|
28d3d5861a | ||
|
|
95d3ef491f | ||
|
|
5c37ddfc6d | ||
|
|
4d9e2d9c91 | ||
|
|
0b1c18913d | ||
|
|
7aee2d805d | ||
|
|
06f03f399a | ||
|
|
c8c2355d3e | ||
|
|
3d1366024d | ||
|
|
f6964d2a66 | ||
|
|
de60f70af5 | ||
|
|
8f2e619162 | ||
|
|
fbcef01c55 | ||
|
|
641e0639d4 | ||
|
|
5048573976 | ||
|
|
78e4d8536d | ||
|
|
a01d088205 | ||
|
|
4b1d1a045d | ||
|
|
e2857d00b4 | ||
|
|
a55a71d31a | ||
|
|
acf793f112 | ||
|
|
2d58ea28ea | ||
|
|
b21de78eb5 | ||
|
|
376d4b4ee1 | ||
|
|
e39304c7cf | ||
|
|
7cba9cda0c | ||
|
|
04c690e8f9 | ||
|
|
170d0fbc9d | ||
|
|
40d632a7b1 | ||
|
|
2e754d23f4 | ||
|
|
5639a4b37c | ||
|
|
8c959f8a60 | ||
|
|
d42c9a6e15 | ||
|
|
da4dabc3f5 | ||
|
|
92217905f8 | ||
|
|
598441a727 | ||
|
|
f707cb19a4 | ||
|
|
63fc408be6 | ||
|
|
69dedd8c22 | ||
|
|
5480805754 | ||
|
|
655ae65b8d | ||
|
|
1a23cb672e | ||
|
|
19e18b4089 | ||
|
|
3d909d5012 | ||
|
|
ad521948b6 | ||
|
|
2f3b6a28c1 | ||
|
|
c779da674c | ||
|
|
d9b140f9f2 | ||
|
|
052648023e | ||
|
|
f5d12d440e | ||
|
|
99d7a90863 | ||
|
|
901d5c86e6 | ||
|
|
df9efd05e6 | ||
|
|
26b8adaec4 | ||
|
|
fc6f5a0336 | ||
|
|
f823a887b7 | ||
|
|
b346d4d85d | ||
|
|
70bd035898 | ||
|
|
7e5cdd8e06 | ||
|
|
a21dac60e0 | ||
|
|
9bd2e0d96e | ||
|
|
dd15a000e1 | ||
|
|
ebcfa44f22 | ||
|
|
43845adb71 | ||
|
|
9e3fff65a7 | ||
|
|
05c35a3a3a | ||
|
|
6f46965344 | ||
|
|
27ee576340 | ||
|
|
58492328df | ||
|
|
fd102bede1 | ||
|
|
3d8c47eefa | ||
|
|
c4e43228a2 | ||
|
|
6526090b8b | ||
|
|
094a018b5b | ||
|
|
a0a9c994b2 | ||
|
|
524ed90e3f | ||
|
|
7abba750b4 | ||
|
|
ecff1641d2 | ||
|
|
47ecf04386 | ||
|
|
c4697a9f45 | ||
|
|
53d5414492 | ||
|
|
311f5c09f5 | ||
|
|
be4439451f | ||
|
|
09c83e83ba | ||
|
|
bea4c64d85 | ||
|
|
0387dcd444 | ||
|
|
a89f21dafd | ||
|
|
7921c05d55 | ||
|
|
dafa946937 | ||
|
|
95673b0131 | ||
|
|
0118136869 | ||
|
|
573c2a7ad6 | ||
|
|
41977ea758 | ||
|
|
75ccded612 | ||
|
|
2429111a59 | ||
|
|
c475cb292e | ||
|
|
04d34b369a | ||
|
|
cfe4c6c559 | ||
|
|
4d13f99d22 | ||
|
|
62ebd4d8a9 | ||
|
|
026c25621f | ||
|
|
c096ae299d | ||
|
|
ae306d1761 | ||
|
|
4caae32933 | ||
|
|
6bbf20980e | ||
|
|
0fd00ecab8 | ||
|
|
70de73a95b | ||
|
|
578ad69c36 | ||
|
|
af263b8c88 | ||
|
|
bef6775de5 | ||
|
|
3c27450e82 | ||
|
|
9400f27f82 | ||
|
|
c176313f7b | ||
|
|
77461d5a23 | ||
|
|
a5c039bf11 | ||
|
|
e3c08f23bf | ||
|
|
67a26e93e4 | ||
|
|
a1d261b7c8 | ||
|
|
3826394940 | ||
|
|
791a54aeec | ||
|
|
48f1bb7755 | ||
|
|
53e028325f | ||
|
|
02eda0a1e2 | ||
|
|
92600160ff | ||
|
|
6ec67a7faf | ||
|
|
a4386744a2 | ||
|
|
09210279e1 | ||
|
|
e78cf18a38 | ||
|
|
9d1d7bbf72 | ||
|
|
60d5e85b4c | ||
|
|
2c263e216f | ||
|
|
e1f671a5b3 | ||
|
|
7ffaea48cb | ||
|
|
0e4527613c | ||
|
|
f363621de3 | ||
|
|
4901ec3b5d | ||
|
|
c592b8a53f | ||
|
|
325e4e44dc | ||
|
|
a81f7f6cfd | ||
|
|
31b83e9675 | ||
|
|
dc89f33cd0 | ||
|
|
f5f9237a78 | ||
|
|
4429ff0ac1 | ||
|
|
a0d38e6b10 | ||
|
|
c060664f84 | ||
|
|
10f7f15f70 | ||
|
|
d40ff29337 | ||
|
|
7ca666ae98 | ||
|
|
dcaea9d40b | ||
|
|
b878273d81 | ||
|
|
c15d29f2da | ||
|
|
3e3a13070a | ||
|
|
11bcd84e66 | ||
|
|
44b63e5953 | ||
|
|
fb0634a0f4 | ||
|
|
0b651db35b | ||
|
|
b24062b575 | ||
|
|
35c5c4cfc0 | ||
|
|
4b8bf57d1a | ||
|
|
a81f0d911a | ||
|
|
28e2227989 | ||
|
|
4f97b6836a | ||
|
|
5ab0dfaba8 | ||
|
|
66751fa006 | ||
|
|
f1d78e4805 | ||
|
|
715c78a04f | ||
|
|
0cd8b4ee8c | ||
|
|
c6efa475a5 | ||
|
|
e846e1fdd7 | ||
|
|
4221067f8f | ||
|
|
36951d6f19 | ||
|
|
ac45500e35 | ||
|
|
0f22eab8b9 | ||
|
|
5a8fd6d518 | ||
|
|
60ee04b9b9 | ||
|
|
d99b5bd505 | ||
|
|
6312c1f99b | ||
|
|
ef870a510f | ||
|
|
394ff05626 | ||
|
|
e90ccfdd20 | ||
|
|
92a86e324b | ||
|
|
e5d6816392 | ||
|
|
a1b2de16a3 | ||
|
|
f605021cfb | ||
|
|
619a2ccb3a | ||
|
|
0cc077c346 | ||
|
|
e34aad991b | ||
|
|
2a925cdd6a | ||
|
|
36c5e444ca | ||
|
|
c7f6041aa4 | ||
|
|
68401b3556 | ||
|
|
3843064eac | ||
|
|
d0de9073e7 | ||
|
|
35bd0ec5d8 | ||
|
|
373a69abbd | ||
|
|
9fa56bf76c | ||
|
|
3ad42fc7e0 | ||
|
|
7dd6efafb2 | ||
|
|
61e26df637 | ||
|
|
a47283bf5b | ||
|
|
d7e5385b04 | ||
|
|
8eaac83238 | ||
|
|
9fbe224f00 | ||
|
|
26dc7b2f65 | ||
|
|
bb6b6f9690 | ||
|
|
0fabfc9873 | ||
|
|
9c3e057410 | ||
|
|
f4cbb1ec73 | ||
|
|
1175f589eb | ||
|
|
8c7563d7f2 | ||
|
|
33533cbb09 | ||
|
|
0ec37a7b95 | ||
|
|
f3db0c171b | ||
|
|
cd10d23371 | ||
|
|
d60c88c506 | ||
|
|
7266aab4be | ||
|
|
54c2ef7a0b | ||
|
|
b882a72d77 | ||
|
|
1eab4dac96 | ||
|
|
b2376aea70 | ||
|
|
1641cfbd03 | ||
|
|
f27540ca02 | ||
|
|
b4320de291 | ||
|
|
1b26aa4b36 | ||
|
|
1ca91f35e2 | ||
|
|
1c5ac56ecf | ||
|
|
ee85e13206 | ||
|
|
440474d53b | ||
|
|
d9c251b2ce | ||
|
|
975b4aee2a | ||
|
|
4a7413a8d9 | ||
|
|
593b34bfe3 | ||
|
|
691b1721b2 | ||
|
|
b8133b4300 | ||
|
|
0c459b98db | ||
|
|
060725642f | ||
|
|
eaf28bf016 | ||
|
|
ed6084c40b | ||
|
|
e56063b065 | ||
|
|
f8ddfb1638 | ||
|
|
900f2e1f76 | ||
|
|
00c9e05a65 | ||
|
|
ecaab51315 | ||
|
|
2a4d45714c | ||
|
|
6e13ef5cbc | ||
|
|
f48e2ab238 | ||
|
|
0e34d976c0 | ||
|
|
2d6cd4c6da | ||
|
|
4a4b3ef5b4 | ||
|
|
67e6167b55 | ||
|
|
79b33bfbd8 | ||
|
|
f5fc96ee3b | ||
|
|
691571ec39 | ||
|
|
f2b20a646e | ||
|
|
bef9ff86d2 | ||
|
|
ff3da5f2db | ||
|
|
129727d5d1 | ||
|
|
6e26b4d5f9 | ||
|
|
371bb11ce8 | ||
|
|
556196ae3f | ||
|
|
f5667411d7 | ||
|
|
774f419a53 | ||
|
|
9fa5d40306 | ||
|
|
ba89d5ec1e | ||
|
|
b7fa577d9b | ||
|
|
949425d14d | ||
|
|
2cb0d63750 | ||
|
|
038aa47578 | ||
|
|
c833598c26 | ||
|
|
489c52361a | ||
|
|
9edf41a2f2 | ||
|
|
5bcca99f60 | ||
|
|
1b0a310fc7 | ||
|
|
e3e7fa3040 | ||
|
|
5297dd6f11 | ||
|
|
c557e93255 | ||
|
|
ad5f0c987a | ||
|
|
30aa6d035d | ||
|
|
b198289fc4 | ||
|
|
51e45085f1 | ||
|
|
97ebb2dccc | ||
|
|
29d28bd3f4 | ||
|
|
09c5c040f2 | ||
|
|
6e60a2f9dc | ||
|
|
5d36108113 | ||
|
|
f4a423ebe5 | ||
|
|
9942fbe549 | ||
|
|
dbde7521e4 | ||
|
|
6eee3e8368 | ||
|
|
cc0ccd7830 | ||
|
|
7ad25249a9 | ||
|
|
687c7d54ff | ||
|
|
d6fff1ffdf | ||
|
|
20a8b8892e | ||
|
|
5c09ecc98d | ||
|
|
19539a2c9d | ||
|
|
5c093c7f22 | ||
|
|
c43ed90607 | ||
|
|
a85242d9c5 | ||
|
|
722d2a9c6c | ||
|
|
f7d65ff52c | ||
|
|
7bee2be12d | ||
|
|
326649d4f5 | ||
|
|
6aba5df55d | ||
|
|
57bbcf9425 | ||
|
|
08ba34d607 | ||
|
|
4c122227a7 | ||
|
|
e14afb4dad | ||
|
|
472def49f6 | ||
|
|
90549893e3 | ||
|
|
73a8e45202 | ||
|
|
35df55cb4f | ||
|
|
c2028d20a8 | ||
|
|
eaffdc6a98 | ||
|
|
0b1e6100a9 | ||
|
|
2168905c11 | ||
|
|
f955e6a299 | ||
|
|
98f3981e12 | ||
|
|
82f94d20ea | ||
|
|
fbc6d47117 | ||
|
|
6a2e4cf813 | ||
|
|
4aabef7683 | ||
|
|
74ae91ee1b | ||
|
|
8b62766474 | ||
|
|
2995504916 | ||
|
|
63f6848d26 | ||
|
|
988e429693 | ||
|
|
ba1c6ef046 | ||
|
|
7ceff92a4e | ||
|
|
1f968b2836 | ||
|
|
d97d7e3b14 | ||
|
|
5c4c4811e4 | ||
|
|
f2a6e63a20 | ||
|
|
1aace4a26f | ||
|
|
b1c140d23e | ||
|
|
ee16212c31 | ||
|
|
f6d232b1c5 | ||
|
|
c8a002933e | ||
|
|
4757ca9913 | ||
|
|
5264c75e37 | ||
|
|
032bf44863 | ||
|
|
2f4f5e43f3 | ||
|
|
7b1edcadf6 | ||
|
|
f0f74d182d | ||
|
|
59142adbbc | ||
|
|
2fda8c5db1 | ||
|
|
7b5efa3e42 | ||
|
|
d784d202bd | ||
|
|
8833474a43 | ||
|
|
57cbb2f8b6 | ||
|
|
b6112a914f | ||
|
|
2008f8538c | ||
|
|
09fba43a1c | ||
|
|
b76c3613f9 | ||
|
|
cf4ddcb587 | ||
|
|
696106f48b | ||
|
|
fb286cd9cf | ||
|
|
5121bd700e | ||
|
|
6173520ad0 | ||
|
|
a7189232dd | ||
|
|
4a96b45b04 | ||
|
|
20ac549dd6 | ||
|
|
38be00c0b7 | ||
|
|
0a9bdc8cf6 | ||
|
|
0b4318280a | ||
|
|
b1da60e1c0 | ||
|
|
2cc5987f9e | ||
|
|
745415a1d8 | ||
|
|
c80658f368 | ||
|
|
033675a417 | ||
|
|
3dd57e9dc8 | ||
|
|
1e3daa6c98 | ||
|
|
8855f51cfc | ||
|
|
50d8debb2b | ||
|
|
e682eb78b0 | ||
|
|
bd2bbf3e2d | ||
|
|
f38f040aea | ||
|
|
f912b2d802 | ||
|
|
0ad03e6a0b | ||
|
|
160d8c529e | ||
|
|
28edfd810c | ||
|
|
7b931cfb66 | ||
|
|
5575c61577 | ||
|
|
8f93dce105 | ||
|
|
0eb3d7226a | ||
|
|
a9533b666c | ||
|
|
6d67b4db56 | ||
|
|
1b5eff6454 | ||
|
|
83fb28cc9d | ||
|
|
c39ffc0b0e | ||
|
|
23892cfbdd | ||
|
|
3bdabc444d | ||
|
|
c233be4467 | ||
|
|
8468f33803 | ||
|
|
0e77369fdb | ||
|
|
9fcc8e7977 | ||
|
|
538371ced8 | ||
|
|
380887bd22 | ||
|
|
17b4b1cb86 | ||
|
|
3e7c358c07 | ||
|
|
05b592a173 | ||
|
|
e1d0515fae | ||
|
|
d4d3b9645e | ||
|
|
d12d99dcfa | ||
|
|
174324d21c | ||
|
|
26156a5982 | ||
|
|
af5ddf6950 | ||
|
|
2ef35e5fb9 | ||
|
|
513bfeaae7 | ||
|
|
7311e6f484 | ||
|
|
90ecedcae8 | ||
|
|
352a20ac48 | ||
|
|
b1d8c5f6ea | ||
|
|
6497be9e52 | ||
|
|
40a8cee8e5 | ||
|
|
112cfcac90 | ||
|
|
8016fcbd54 | ||
|
|
6de97f1d03 | ||
|
|
204075bbe0 | ||
|
|
eb448bce37 | ||
|
|
3d09b5cb67 | ||
|
|
35d06040f7 | ||
|
|
0868e81944 | ||
|
|
7efbeb7d0f | ||
|
|
815f61b550 | ||
|
|
c3a90ab499 | ||
|
|
321126afa2 | ||
|
|
9ad4a9c3c9 | ||
|
|
b12f7c7ce4 | ||
|
|
6d7d3c0794 | ||
|
|
92b988a8d5 | ||
|
|
18952ee2bd | ||
|
|
bff07888f9 | ||
|
|
8e6b0b220a | ||
|
|
74acb0d078 | ||
|
|
d4727eea02 | ||
|
|
76d14eba0c | ||
|
|
90d05d9260 | ||
|
|
23b24bbb6c | ||
|
|
91bc6f07c5 | ||
|
|
9b2181667d | ||
|
|
40347e3e46 | ||
|
|
ed277f6e16 | ||
|
|
8f2085d8b4 | ||
|
|
b5a48ad201 | ||
|
|
14b900791f | ||
|
|
de80799e68 | ||
|
|
53eca387fc | ||
|
|
fc3005f271 | ||
|
|
c95fdff00c | ||
|
|
3cd9042c72 | ||
|
|
4d3914426e | ||
|
|
af1fb7041e | ||
|
|
e2eb1bf223 | ||
|
|
5a64a6f1a3 | ||
|
|
88aa9303d7 | ||
|
|
5c77eec184 | ||
|
|
a931ed7c01 | ||
|
|
94cd2b618c | ||
|
|
9c97fc258d | ||
|
|
0ac1cfe555 | ||
|
|
3942f1bc33 | ||
|
|
a66e38a901 | ||
|
|
f65f4f4aeb | ||
|
|
f28b13bf87 | ||
|
|
8f211a0785 | ||
|
|
ba1dfb2851 | ||
|
|
964d56752e | ||
|
|
cb6a66eba5 | ||
|
|
94adf7259d | ||
|
|
3c831b549a | ||
|
|
7ccf36a0fa | ||
|
|
b0ee640c12 | ||
|
|
cd6d41a035 | ||
|
|
9c8f1f3e11 | ||
|
|
7c50a5a456 | ||
|
|
f3b6703fd4 | ||
|
|
60f2716b5a | ||
|
|
d7007ef99d | ||
|
|
4aca41cdbb | ||
|
|
7e31fac99a | ||
|
|
3bcf1cb6b5 | ||
|
|
a29cc74304 | ||
|
|
95c43d0864 | ||
|
|
369b958335 | ||
|
|
9a17da8f65 | ||
|
|
0c4ba20d6e | ||
|
|
22936ff6c9 | ||
|
|
3369ad0bdc | ||
|
|
20853ef60b | ||
|
|
da0c66bd8e | ||
|
|
44664917ff | ||
|
|
ce26e002c7 | ||
|
|
345b9f546c | ||
|
|
f4ed5e301d | ||
|
|
4818f851b3 | ||
|
|
6f2c47c0ca | ||
|
|
5e6bc0f0df | ||
|
|
083daa0b76 | ||
|
|
139a10ba8c | ||
|
|
0b512487f5 | ||
|
|
a85adfdf1f | ||
|
|
0171b785af | ||
|
|
4c1c484af9 | ||
|
|
db7585b6b6 | ||
|
|
d263f6d929 | ||
|
|
034c28e487 | ||
|
|
9a88f57ce6 | ||
|
|
28415646a2 | ||
|
|
b03295ef81 | ||
|
|
7d3e849ff3 | ||
|
|
926f20a6a4 | ||
|
|
c12d577ce6 | ||
|
|
aa8d3a9841 | ||
|
|
f11e03eb85 | ||
|
|
ab996b5189 | ||
|
|
4c91e730a2 | ||
|
|
5ca5f44c61 | ||
|
|
f8a89b1c0d | ||
|
|
99dacef747 | ||
|
|
24fc37105e | ||
|
|
cbd493d834 | ||
|
|
53dbd1aedf | ||
|
|
6ab1af54aa | ||
|
|
615d9758bb | ||
|
|
341f9f8c91 | ||
|
|
ba7d4a5215 | ||
|
|
428187ad81 | ||
|
|
fe96172fcd | ||
|
|
8b13be698c | ||
|
|
5edc924e4f | ||
|
|
78c50a4339 | ||
|
|
607284585c | ||
|
|
f7af352f03 | ||
|
|
008ec2c88c | ||
|
|
c91074ad91 | ||
|
|
51fbb619e5 | ||
|
|
062c4b335b | ||
|
|
d4107e273d | ||
|
|
4dad67fc2e | ||
|
|
64b0713742 | ||
|
|
22c45e788e | ||
|
|
75de544669 | ||
|
|
768ec10809 | ||
|
|
4d5d9be399 | ||
|
|
7f4afc111e | ||
|
|
0365f883dd | ||
|
|
6f98549f31 | ||
|
|
77920818d9 | ||
|
|
0682d54ee2 | ||
|
|
fbcc3b2fa2 | ||
|
|
c3f47b2ecb | ||
|
|
8b9f59ac5a | ||
|
|
362dcabe5c | ||
|
|
6e205661bd | ||
|
|
c1a8627702 | ||
|
|
2c5253943c | ||
|
|
03668216fa | ||
|
|
37ef234803 | ||
|
|
d25aa97fca | ||
|
|
17dc973305 | ||
|
|
eed4e4a134 | ||
|
|
5fd28c6cad | ||
|
|
0f69ea197d | ||
|
|
e1a214e1a8 | ||
|
|
e7e14750cb | ||
|
|
cb83013967 | ||
|
|
0a84e1bb7b | ||
|
|
aee7f4988a | ||
|
|
e762c402fa | ||
|
|
4375cae70d | ||
|
|
90268a9041 | ||
|
|
a3ebc4df45 | ||
|
|
b2743c76e0 | ||
|
|
969a70d571 | ||
|
|
e6a538dbd7 | ||
|
|
9cffce55c9 | ||
|
|
7bc91d7e99 | ||
|
|
943f5feb59 | ||
|
|
dc72dbbc97 | ||
|
|
1513a1e2d2 | ||
|
|
82989cae57 | ||
|
|
74f8a5053e | ||
|
|
79f7ea209a | ||
|
|
ba65e35c51 | ||
|
|
5bc4e3ce3b | ||
|
|
1c7ac60c11 | ||
|
|
00cd54b69c | ||
|
|
90e3a3f0c7 | ||
|
|
5eef3fc42a | ||
|
|
83a8474731 | ||
|
|
a5e13c5152 | ||
|
|
b19f53d380 | ||
|
|
abadef1d2e | ||
|
|
a3d976c5b8 | ||
|
|
414b20f06d | ||
|
|
d03a442b6c | ||
|
|
e5acce03e5 | ||
|
|
fe714d4515 | ||
|
|
7959344bca | ||
|
|
b9582f171d | ||
|
|
410123d933 | ||
|
|
ae484443d8 | ||
|
|
9d97e56f03 | ||
|
|
01269ec1ef | ||
|
|
a204264bcc | ||
|
|
eb0a048926 | ||
|
|
ba1509b37a | ||
|
|
ad379e7a32 | ||
|
|
9d45beea3b | ||
|
|
b2d134aeb4 | ||
|
|
d500b8ea19 | ||
|
|
8b3df4b373 | ||
|
|
f01fc7c8ba | ||
|
|
0e6da0bffa | ||
|
|
eab8b1c2bf | ||
|
|
8b42a0fede | ||
|
|
4bbe078230 | ||
|
|
aabb931d27 | ||
|
|
b1c1b21975 | ||
|
|
7b5dc3ef96 | ||
|
|
1f831f90e0 | ||
|
|
ef2c1b51e9 | ||
|
|
ace73c041b | ||
|
|
3c70fe5303 | ||
|
|
137e23c025 | ||
|
|
969a19d515 | ||
|
|
7536abe96c | ||
|
|
8e20e163f9 | ||
|
|
adbe8e1f67 | ||
|
|
5db134f34f | ||
|
|
80cf7c1dd2 | ||
|
|
9e5cc184ed | ||
|
|
a5185b456c | ||
|
|
0615198ad2 | ||
|
|
6cd422f5b3 | ||
|
|
4416178d6f | ||
|
|
b8cef99dc1 | ||
|
|
4dcb68af33 | ||
|
|
b4c70ab14a | ||
|
|
8436e17af9 | ||
|
|
bda04cbdc7 | ||
|
|
7287947a55 | ||
|
|
fb5eb1e19c | ||
|
|
d735dcdc3e | ||
|
|
83d8a61400 | ||
|
|
b72f57c040 | ||
|
|
8a7ef1c704 | ||
|
|
8731bc13d1 | ||
|
|
d103cda0c8 | ||
|
|
ca4e864e46 | ||
|
|
0e25950d51 | ||
|
|
2c29a90b5e | ||
|
|
2900836208 | ||
|
|
928a1df525 | ||
|
|
16e0dff551 | ||
|
|
7e443d5c9b | ||
|
|
172ae17966 | ||
|
|
8cbf7b5d0a | ||
|
|
2c40b85880 | ||
|
|
ad388f23ae | ||
|
|
27b559a2d8 | ||
|
|
c6d19e14c5 | ||
|
|
b807dca2d8 | ||
|
|
2cae6e3f59 | ||
|
|
69c73f3dcd | ||
|
|
4456ab2cd5 | ||
|
|
bdda18de23 | ||
|
|
1b2c2f3d41 | ||
|
|
fd19d29ef6 | ||
|
|
1f0c0fd756 | ||
|
|
83698cc52d | ||
|
|
70b94deb20 | ||
|
|
2da3df6e4d | ||
|
|
509e633a69 | ||
|
|
17fac2b82a | ||
|
|
c543c4e10a | ||
|
|
10073800dc | ||
|
|
04c38250b4 | ||
|
|
5ccb329af1 | ||
|
|
3cecb53bc5 | ||
|
|
0daf431d68 | ||
|
|
3e0c4242ad | ||
|
|
17b775c377 | ||
|
|
4525b98288 | ||
|
|
755699d479 | ||
|
|
a84309b800 | ||
|
|
16863535b8 | ||
|
|
dd9773d72e | ||
|
|
ec45f6c0ee | ||
|
|
59235630bb | ||
|
|
11ed0ca89b | ||
|
|
188ea6e8e2 | ||
|
|
293b464d9f | ||
|
|
0e91aa521e | ||
|
|
5272593cc3 | ||
|
|
c5f336b0e4 | ||
|
|
b1a6fa3ffc | ||
|
|
fe47134934 | ||
|
|
131cc606f0 | ||
|
|
3681f01fad | ||
|
|
e966c112ab | ||
|
|
d7b232b00b | ||
|
|
7986509ad3 | ||
|
|
73dcf970f3 | ||
|
|
9377aa2d05 | ||
|
|
686fa5a5ed | ||
|
|
c946ae6eab | ||
|
|
9b2f1d9415 | ||
|
|
f6c28aa8e2 | ||
|
|
64c72aa6f5 | ||
|
|
0a22917773 | ||
|
|
3c4888e52b | ||
|
|
9d31f1ba07 | ||
|
|
d722d17a02 | ||
|
|
522d929f5a | ||
|
|
42037074cb | ||
|
|
1e3f17efdf | ||
|
|
7389e0075d | ||
|
|
a080114690 | ||
|
|
1293848d9b | ||
|
|
16b2d9e873 | ||
|
|
7a64334261 | ||
|
|
009b20c95a | ||
|
|
296bea1b88 | ||
|
|
e0775607cc | ||
|
|
a1fb4b8bf3 | ||
|
|
29ae78c193 | ||
|
|
46cfb42cce | ||
|
|
94ef9f4dbe | ||
|
|
b864e992ef | ||
|
|
57ed9a4226 | ||
|
|
b2c93cbeda | ||
|
|
60540dadee | ||
|
|
c0236650f0 | ||
|
|
fb3017cfff | ||
|
|
2c327cfdf6 | ||
|
|
307f2efc97 | ||
|
|
929c91a48c | ||
|
|
bfd9595c1c | ||
|
|
c091f9a8ae | ||
|
|
d5b71b302b | ||
|
|
67103232be | ||
|
|
f471fc3d2b | ||
|
|
2a0783d005 | ||
|
|
7234ad261b | ||
|
|
001d1fb8d3 | ||
|
|
35a56bf37c | ||
|
|
9715ff061e | ||
|
|
9866db9ced | ||
|
|
fc2288a583 | ||
|
|
11d1bbe222 | ||
|
|
bc07256d8e | ||
|
|
3826bdb0c3 | ||
|
|
9609dddd47 | ||
|
|
64c51f0d94 | ||
|
|
ad7b318da0 | ||
|
|
66c76ea6b5 | ||
|
|
29e47c1e90 | ||
|
|
e08a074a1c | ||
|
|
d7ebb30e05 | ||
|
|
8330068434 | ||
|
|
42dea4a2eb | ||
|
|
4de0ae6628 | ||
|
|
5a714af309 | ||
|
|
20f73fdae7 | ||
|
|
aca91cf18f | ||
|
|
974a7d7520 | ||
|
|
f9d7545f7d | ||
|
|
0e135c4645 | ||
|
|
961f847765 | ||
|
|
b83fed4701 | ||
|
|
651fd2aca7 | ||
|
|
2dd863e711 | ||
|
|
bac5ea7ea6 | ||
|
|
312db7eec3 | ||
|
|
31850b3a71 | ||
|
|
ee35e39611 | ||
|
|
872130d65c | ||
|
|
b903554f52 | ||
|
|
c3fba20780 | ||
|
|
870d2da8ed | ||
|
|
22d17f6c8e | ||
|
|
6bbf12a660 | ||
|
|
ab4ae742db | ||
|
|
7725071ae2 | ||
|
|
c7ab6ebec7 | ||
|
|
d56abadf4c | ||
|
|
7eb2952ec5 | ||
|
|
21cf2d5437 | ||
|
|
5af0c448c6 | ||
|
|
2ca9392c5a | ||
|
|
a5a6f2dcc4 | ||
|
|
91f5207d68 | ||
|
|
c89848dec0 | ||
|
|
116d3ec319 | ||
|
|
20266a229b | ||
|
|
0a26e84f8f | ||
|
|
93bfa7a575 | ||
|
|
c09991573c | ||
|
|
556b7b26d4 | ||
|
|
a011600766 | ||
|
|
2e5439c385 | ||
|
|
3d6ae08437 | ||
|
|
03228f7952 | ||
|
|
e46a8c4369 | ||
|
|
01ef92a795 | ||
|
|
61a5d18be6 | ||
|
|
9c2c48bd59 | ||
|
|
df6d49b2ac | ||
|
|
2476bf76b5 | ||
|
|
1c4a397249 | ||
|
|
4930018a55 | ||
|
|
205f4c31d6 | ||
|
|
89d3c87919 | ||
|
|
d0a861d39c | ||
|
|
9f7b96c727 | ||
|
|
e1d2a8b41d | ||
|
|
e71bf9c288 | ||
|
|
693ea3a40e | ||
|
|
921d23e73f | ||
|
|
709944c859 | ||
|
|
9341c19bd5 | ||
|
|
1cee84d9af | ||
|
|
bea5fe5474 | ||
|
|
c473f2b284 | ||
|
|
d5c163ac48 | ||
|
|
85dcef1b2e | ||
|
|
8c1acc6758 | ||
|
|
fbb7f0a6a1 | ||
|
|
3b7c8963df | ||
|
|
d58f4a73b6 | ||
|
|
09cfd85603 | ||
|
|
846a301122 | ||
|
|
6a29925733 | ||
|
|
5633350b63 | ||
|
|
5d5ffcdb36 | ||
|
|
a819835984 | ||
|
|
227721bfd3 | ||
|
|
31e2cc5f07 | ||
|
|
3f02cf0561 | ||
|
|
a57a9f0386 | ||
|
|
11a6df6e19 | ||
|
|
8d5e1feac9 | ||
|
|
e19e3d7380 | ||
|
|
78c7664be3 | ||
|
|
39b29fe0ea | ||
|
|
5636edc1d1 | ||
|
|
7dbdc75cad | ||
|
|
fd92c916b7 | ||
|
|
f5e880839e | ||
|
|
6e70172c45 | ||
|
|
22563bf671 | ||
|
|
cad95403aa | ||
|
|
d375595e08 | ||
|
|
b16d13cc35 | ||
|
|
f03471ee39 | ||
|
|
6f1f65487d | ||
|
|
b863aaedb3 | ||
|
|
b77994d01f | ||
|
|
30e01c07f7 | ||
|
|
1e018b82df | ||
|
|
49e6966037 | ||
|
|
85b1df46cd | ||
|
|
6908a2cd2b | ||
|
|
4379d818ab | ||
|
|
4434dfb79a | ||
|
|
9621f67e84 | ||
|
|
21a0684353 | ||
|
|
3601955433 | ||
|
|
d91483c485 | ||
|
|
8b3d07906f | ||
|
|
5f8a4b6be4 | ||
|
|
f8ff919787 | ||
|
|
6dfe975fc7 | ||
|
|
2650f8d3dd | ||
|
|
f172b6ceaa | ||
|
|
8086af1bf7 | ||
|
|
5813840e17 | ||
|
|
e2d595394a | ||
|
|
9b24e6fb1f | ||
|
|
0f33144935 | ||
|
|
6d384166d5 | ||
|
|
8b766dc242 | ||
|
|
7a0b4c4d23 | ||
|
|
f45edbc4f0 | ||
|
|
65d3355b18 | ||
|
|
1fa64c836c | ||
|
|
af700c1481 | ||
|
|
7dcf16cd97 | ||
|
|
f86b46076c | ||
|
|
6fe58d7b73 | ||
|
|
8c2a4b5cae | ||
|
|
b2c31f5166 | ||
|
|
0f4d0ff986 | ||
|
|
2b73f9cafd | ||
|
|
a86438a265 | ||
|
|
c0b5102d31 | ||
|
|
feab3a38f9 | ||
|
|
b1fb9c5c47 | ||
|
|
9fb65f46a1 | ||
|
|
7a2e85b856 | ||
|
|
f85e3e76fd | ||
|
|
c6ef02d0a6 | ||
|
|
81a6e3cf4e | ||
|
|
48a75927f6 | ||
|
|
067a85ef88 | ||
|
|
c4757313e6 | ||
|
|
88d8998bd2 | ||
|
|
97e6884487 | ||
|
|
8fd56dbc38 | ||
|
|
f9c97ad5cb | ||
|
|
f893aba522 | ||
|
|
f2740aaee2 | ||
|
|
fb15cc135a | ||
|
|
d9579914b4 | ||
|
|
5a98bfd8ef | ||
|
|
149e6ebf84 | ||
|
|
74c8e512a7 | ||
|
|
52bf9b87fa | ||
|
|
ac8d71215e | ||
|
|
c7cfedb874 | ||
|
|
faae40c9e8 | ||
|
|
288912ccea | ||
|
|
26e47c3e33 | ||
|
|
15a8ea6598 | ||
|
|
aeda6d3312 | ||
|
|
79f430efb3 | ||
|
|
4fe70de2ff | ||
|
|
56fd6d6a5b | ||
|
|
b5076edc8d | ||
|
|
4fbb9e232c | ||
|
|
b6324d9cee | ||
|
|
f668f725e8 | ||
|
|
e45041f2f2 | ||
|
|
d285076acb | ||
|
|
9047aae87c | ||
|
|
44b00edcb6 | ||
|
|
a476c2a167 | ||
|
|
1b2b168624 | ||
|
|
ce238bcd1d | ||
|
|
c119a82d83 | ||
|
|
4b97686a26 | ||
|
|
c13350b098 | ||
|
|
c9c6df4861 | ||
|
|
2e73681aae | ||
|
|
42b4c25ca3 | ||
|
|
5a5939408f | ||
|
|
7041bac8ca | ||
|
|
f8ab02fdab | ||
|
|
b75ba4b4aa | ||
|
|
baa80d08dd | ||
|
|
144d40cd38 | ||
|
|
c6b4610adf | ||
|
|
f2c5cd978b | ||
|
|
63823698c7 | ||
|
|
f6ca679a57 | ||
|
|
142c46c127 | ||
|
|
1bd59523b2 | ||
|
|
ef67925858 | ||
|
|
5dae376bcb | ||
|
|
14ed325579 | ||
|
|
b007409521 | ||
|
|
5830252df7 | ||
|
|
02ad9587fc | ||
|
|
4596336c13 | ||
|
|
2a413256ed | ||
|
|
8b9178249d | ||
|
|
1d0ba36d7c | ||
|
|
3a8211937f | ||
|
|
0d576f7011 | ||
|
|
d90e81b0e5 | ||
|
|
89be1767e9 | ||
|
|
aee6921140 | ||
|
|
a55572d52f | ||
|
|
525deafd83 | ||
|
|
8064b969be | ||
|
|
6d6e12bbd0 | ||
|
|
825ae48000 | ||
|
|
764aef3181 | ||
|
|
d226abadc1 | ||
|
|
ccd1fa3a0f | ||
|
|
65a692e3bf | ||
|
|
2daac955f4 | ||
|
|
162797e43a | ||
|
|
784b29805a | ||
|
|
67b60cff60 | ||
|
|
28443de11f | ||
|
|
59cf60c2ba | ||
|
|
8e14a1e2ec | ||
|
|
7dd2e5ec98 | ||
|
|
bd3e052130 | ||
|
|
6fbe7efcab | ||
|
|
572a574bf3 | ||
|
|
347a0a43ea | ||
|
|
28abd00a6e | ||
|
|
06354d6d1d | ||
|
|
2b31d54e18 | ||
|
|
58644b3d5c | ||
|
|
4c732b3b2d | ||
|
|
36d3a0728c | ||
|
|
b0c696e401 | ||
|
|
2a28b5421f | ||
|
|
269176e0a6 | ||
|
|
cd23a68268 | ||
|
|
48e81c8b10 | ||
|
|
649c294929 | ||
|
|
ab0dcb0de9 | ||
|
|
cb2fc8f95b | ||
|
|
5deec4391d | ||
|
|
1873e506e0 | ||
|
|
11e660a81a | ||
|
|
635ba2a7e3 | ||
|
|
1a2fb55d03 | ||
|
|
a5785e526e | ||
|
|
af9d50f5ec | ||
|
|
ac06b9c018 | ||
|
|
36d8df1442 | ||
|
|
a312c4ef1d | ||
|
|
0c6b80d370 | ||
|
|
16f9129acc | ||
|
|
1af9554cc7 | ||
|
|
cc8999cbc9 | ||
|
|
c7b4099758 | ||
|
|
f060fc228f | ||
|
|
8d3c091d2e | ||
|
|
cabf7c1613 | ||
|
|
b44149bbaf | ||
|
|
18befade7f | ||
|
|
8fd8eb703b | ||
|
|
fa0c29c1d1 | ||
|
|
65ed5c98bf | ||
|
|
f0ecf74aad | ||
|
|
c56ed0af28 | ||
|
|
ddb8231c00 | ||
|
|
bc24e8f236 | ||
|
|
2edb31e7ea | ||
|
|
ad619d9b8d | ||
|
|
61f738ce3d | ||
|
|
73ae95ed06 | ||
|
|
6d4c1aa3ea | ||
|
|
34f230a882 | ||
|
|
a68d81e495 | ||
|
|
9687c38e06 | ||
|
|
f69670c368 | ||
|
|
a0b537ef64 | ||
|
|
e8663b5bfc | ||
|
|
9f12fbde70 | ||
|
|
940b16ebd2 | ||
|
|
dc5aa0c30d | ||
|
|
b70b9c44fc | ||
|
|
88a4cf1aa4 | ||
|
|
49eefa131f | ||
|
|
9f4a60572f | ||
|
|
8f9579bcaf | ||
|
|
845dd4115d | ||
|
|
3e2a1227ce | ||
|
|
dcfec014a5 | ||
|
|
f5598ba93e | ||
|
|
a5fadb6e8a | ||
|
|
738ba2d6fd | ||
|
|
ebcc45d1fd | ||
|
|
272a911d35 | ||
|
|
a725e577be | ||
|
|
a36ead9ef1 | ||
|
|
f516072d12 | ||
|
|
a54b36b057 | ||
|
|
a18484a5dd | ||
|
|
e685c0a342 | ||
|
|
a3b1d11bb3 | ||
|
|
7a7643c6bc | ||
|
|
3643bd04f1 | ||
|
|
65c2faaced | ||
|
|
32a91ca98c | ||
|
|
9f6e98a5d0 | ||
|
|
0964a9fd50 | ||
|
|
a0b865cd07 | ||
|
|
a5f73b5c20 | ||
|
|
d10be352be | ||
|
|
6f3d8ddd96 | ||
|
|
1a14e65dcf | ||
|
|
2757dfdb75 | ||
|
|
1b5526235e | ||
|
|
d4836c5fde | ||
|
|
530810e366 | ||
|
|
9f2a4828f4 | ||
|
|
70cc3a612e | ||
|
|
6917ba6230 | ||
|
|
710c06672e | ||
|
|
5d9e14aad1 | ||
|
|
9963cb3770 | ||
|
|
5731ef20b3 | ||
|
|
ab89d34440 | ||
|
|
d9bac2916c | ||
|
|
edaa9610f6 | ||
|
|
90255b1a1b | ||
|
|
639f137ad2 | ||
|
|
29609e04c2 | ||
|
|
736aaf4433 | ||
|
|
2d7248962f | ||
|
|
a13c98c36c | ||
|
|
e298499326 | ||
|
|
6e1e463e1d | ||
|
|
2a2261beaf | ||
|
|
14623f5df2 | ||
|
|
32889779a2 | ||
|
|
911a7e3636 | ||
|
|
bcf8ae2734 | ||
|
|
92df3b1f42 | ||
|
|
5bbed1f9a3 | ||
|
|
0a391760b8 | ||
|
|
e7eeb8cb55 | ||
|
|
bee4f38209 | ||
|
|
ff4dcfc220 | ||
|
|
ad726a97e4 | ||
|
|
b533542792 | ||
|
|
dbe33cc046 | ||
|
|
3ddf5f4bec | ||
|
|
f02d49f181 | ||
|
|
4df68697f2 | ||
|
|
eeb09d9184 | ||
|
|
d8509a145b | ||
|
|
e3cb799638 | ||
|
|
ce9469c85b | ||
|
|
e62b166805 | ||
|
|
a1f283c641 | ||
|
|
2b14c398a8 | ||
|
|
d8480d058b | ||
|
|
b1ac1a36d4 | ||
|
|
3c2d014ad3 | ||
|
|
d940d26312 | ||
|
|
99028b5c99 | ||
|
|
ac94f0659d | ||
|
|
bd85a5a153 | ||
|
|
9aa375a45f | ||
|
|
999cb99eb8 | ||
|
|
12b53bc4bb | ||
|
|
952f3c451f | ||
|
|
ce06375a92 | ||
|
|
c0f60d48bb | ||
|
|
e40f08d467 | ||
|
|
9c977bf90f | ||
|
|
525f32feab | ||
|
|
cdb698f0d1 | ||
|
|
c65d09f4a8 | ||
|
|
7d4e48431c | ||
|
|
6a7268a9c9 | ||
|
|
eea1137abc | ||
|
|
a130121698 | ||
|
|
153f039ee6 | ||
|
|
b7216d28f4 | ||
|
|
ee34139094 | ||
|
|
9addea79b7 | ||
|
|
2c88ace91c | ||
|
|
6eae95f964 | ||
|
|
b44ed7c45a | ||
|
|
b2d2546e39 | ||
|
|
4dbabdf350 | ||
|
|
df63d8fe0f | ||
|
|
c9116575fa | ||
|
|
6707673c7f | ||
|
|
1f82446843 | ||
|
|
9942b0e389 | ||
|
|
f57e8501c4 | ||
|
|
1e9fa003db | ||
|
|
7868b22918 | ||
|
|
e2c80956dc | ||
|
|
5d5af58bdf | ||
|
|
8f78106816 | ||
|
|
1923289c51 | ||
|
|
14c22147d5 | ||
|
|
6d39bc4a20 | ||
|
|
cfaecb590d | ||
|
|
2894c18ba1 | ||
|
|
e6633c2fc6 | ||
|
|
fe341f0851 | ||
|
|
34a387d4bd | ||
|
|
f975d9c8dc | ||
|
|
563ff98c83 | ||
|
|
0b9ecb76b9 | ||
|
|
b8de1de3a8 | ||
|
|
ac2f48684e | ||
|
|
9928b17a76 | ||
|
|
723a6a1fbd | ||
|
|
51ac75943d | ||
|
|
6bcb5eac71 | ||
|
|
f2f1e355c2 | ||
|
|
4cc0754f11 | ||
|
|
cd30caa12d | ||
|
|
41bc74e543 | ||
|
|
96a908698d | ||
|
|
77a561024f | ||
|
|
5d0176e686 | ||
|
|
3a6013145e | ||
|
|
c5e2471f34 | ||
|
|
e9802f2191 | ||
|
|
2d0097fddc | ||
|
|
1a245db4c9 | ||
|
|
6a694f9298 | ||
|
|
acd1f43018 | ||
|
|
71ed9a2db9 | ||
|
|
2b5d9bd213 | ||
|
|
32c8664829 | ||
|
|
26e6e0ab72 | ||
|
|
6d9c9bd884 | ||
|
|
2a74d5eb94 | ||
|
|
04d39e0e8d | ||
|
|
c5e64b39db | ||
|
|
4911585a85 | ||
|
|
590c00114f | ||
|
|
111eded34a | ||
|
|
d767900fb1 | ||
|
|
9074d5390a | ||
|
|
91027459ca | ||
|
|
a2eda6c5af | ||
|
|
338489febd | ||
|
|
94e7820baf | ||
|
|
a47df57709 | ||
|
|
f73d64f732 | ||
|
|
cfaef4c567 | ||
|
|
3ec2c6ded4 | ||
|
|
2afaa35170 | ||
|
|
efcf4a77c6 | ||
|
|
221e1de4e7 | ||
|
|
f2de2983c8 | ||
|
|
82c8499789 | ||
|
|
d66ccdb255 | ||
|
|
8d13c514b0 | ||
|
|
f57aafba19 | ||
|
|
0a7406db15 | ||
|
|
2f97e8b329 | ||
|
|
22a8758852 | ||
|
|
bc6bc1d57a | ||
|
|
4a692b9a88 | ||
|
|
0094f800dc | ||
|
|
9bd616f36f | ||
|
|
4acc36628d | ||
|
|
e550413778 | ||
|
|
ccdc894979 | ||
|
|
322bc71d52 | ||
|
|
7c55e4d234 | ||
|
|
8c8058290c | ||
|
|
9d413bf0eb | ||
|
|
8fde5dd1bf | ||
|
|
2f9ecb9396 | ||
|
|
85092279fa | ||
|
|
d0189523e4 | ||
|
|
a26d03205a | ||
|
|
862eda6dd4 | ||
|
|
4a7f0fc206 | ||
|
|
6bbee58d39 | ||
|
|
989faed410 | ||
|
|
198e2f2043 | ||
|
|
6ae3d4110d | ||
|
|
c34e1be43b | ||
|
|
17a440ad9c | ||
|
|
04dcfc7adb | ||
|
|
ca66e334c1 | ||
|
|
54bba4c92f | ||
|
|
9c046b808c | ||
|
|
ca5d1865cc | ||
|
|
d8f1aa5bc9 | ||
|
|
6ac790e083 | ||
|
|
d0870e4bbb | ||
|
|
5138595f36 | ||
|
|
d9aa5684a9 | ||
|
|
8e2521a7a9 | ||
|
|
7dd7a117cb | ||
|
|
defbadf4d7 | ||
|
|
131e88080a | ||
|
|
fb78b886c1 | ||
|
|
aed0b87b16 | ||
|
|
1316cc6a40 | ||
|
|
944d370c14 | ||
|
|
74f9aa6af6 | ||
|
|
c20c9c9917 | ||
|
|
4801435d72 | ||
|
|
33fd105ef7 | ||
|
|
3ea3fb8984 | ||
|
|
b4bbc544ca | ||
|
|
5f880e920b | ||
|
|
bcce801dd7 | ||
|
|
00f9dcee4a | ||
|
|
505af2bc96 | ||
|
|
c217aab5fc | ||
|
|
5d5fd0028f | ||
|
|
c88693dfdd | ||
|
|
0a16ec1bd2 | ||
|
|
6f36a3c724 | ||
|
|
71496bd1ef | ||
|
|
c5a99a7c12 | ||
|
|
cfaf33d696 | ||
|
|
e24c76d2bf | ||
|
|
b6273205a2 | ||
|
|
b38193aa19 | ||
|
|
f9cfacae23 | ||
|
|
ac46317dc6 | ||
|
|
2b492a5a61 | ||
|
|
a2133657f0 | ||
|
|
e8de45789f | ||
|
|
3d2bd167ca | ||
|
|
504c8626dc | ||
|
|
f4b29dc7e0 | ||
|
|
b34c5c743b | ||
|
|
c57311d6c0 | ||
|
|
4d786dc697 | ||
|
|
062e3e055a | ||
|
|
1465174a45 | ||
|
|
cc00ada5a3 | ||
|
|
cbf312b62d | ||
|
|
2be3144086 | ||
|
|
da3acd9d19 | ||
|
|
34b048479b | ||
|
|
ca92931bf2 | ||
|
|
0d3daeb823 | ||
|
|
58b1d7e0eb | ||
|
|
c5997ed056 | ||
|
|
da1deee7f3 | ||
|
|
a4eaff3175 | ||
|
|
211cfc0bd3 | ||
|
|
c0f85b691d | ||
|
|
6b93d58ea6 | ||
|
|
5bce423b49 | ||
|
|
01b0dde503 | ||
|
|
ed1bc8cb7d | ||
|
|
abe559261b | ||
|
|
b0cdf22cb8 | ||
|
|
a61ba71f1e | ||
|
|
7061d57559 | ||
|
|
83a1e6c87c | ||
|
|
c18888b8de | ||
|
|
2d80935e00 | ||
|
|
4287d158b6 | ||
|
|
4e9b569178 | ||
|
|
5d626d291b | ||
|
|
afa4a01c44 | ||
|
|
3c4a23c5a3 | ||
|
|
8d92c976d9 | ||
|
|
1a9adfad29 | ||
|
|
a9e9a5974d | ||
|
|
27160aa8fe | ||
|
|
6a71af00cf | ||
|
|
6c0938db50 | ||
|
|
b76173c82f | ||
|
|
0bcf2b1ff4 | ||
|
|
d074415a26 | ||
|
|
42f3e38026 | ||
|
|
74c16ee7ba | ||
|
|
f6ef22b917 | ||
|
|
c3f3d7efda | ||
|
|
61d44efdc4 | ||
|
|
ad200c86ec | ||
|
|
4aecf4e0b4 | ||
|
|
d81f37c78b | ||
|
|
c2979ce5ab | ||
|
|
09c7edce88 | ||
|
|
beefb79258 | ||
|
|
529c6ac81c | ||
|
|
84b988ea96 | ||
|
|
35e978efc9 | ||
|
|
19559d01f7 | ||
|
|
56cec343e2 | ||
|
|
20c9bd0130 | ||
|
|
1336997c58 | ||
|
|
b178fdefdc | ||
|
|
453d60060a | ||
|
|
901fac97a0 | ||
|
|
29b6a88343 | ||
|
|
a2217c7fc6 | ||
|
|
3eec30aa42 | ||
|
|
f352e19e90 | ||
|
|
be65ef89bc | ||
|
|
cfc46073c0 | ||
|
|
1819a2bbda | ||
|
|
aa3a42f94e | ||
|
|
4bff55b612 | ||
|
|
dbc4e09909 | ||
|
|
0a074c8a66 | ||
|
|
8b314ebb75 | ||
|
|
4dc0791aeb | ||
|
|
e3483f11b1 | ||
|
|
244a678ab7 | ||
|
|
8e1d44fabc | ||
|
|
954a5b58e0 | ||
|
|
53223bc72b | ||
|
|
a11a1fa07e | ||
|
|
9ab4001544 | ||
|
|
3e3b71d230 | ||
|
|
186929269b | ||
|
|
afa7a04af0 | ||
|
|
2861d12f04 | ||
|
|
65e1212b2f | ||
|
|
47136c8b71 | ||
|
|
375b829562 | ||
|
|
2718d42b01 | ||
|
|
93d4118c0a | ||
|
|
3a2a47af12 | ||
|
|
0eacdfca85 | ||
|
|
a7388be25f | ||
|
|
5fcdcb1275 | ||
|
|
4635bdffb0 | ||
|
|
72b1c36111 | ||
|
|
fc5ff601a8 | ||
|
|
8dd142fc9f | ||
|
|
97f24293e2 | ||
|
|
f4beba5215 | ||
|
|
e2abe0f52a | ||
|
|
5d18643374 | ||
|
|
769f2a30c2 | ||
|
|
0e040d7744 | ||
|
|
7600d0a44e | ||
|
|
9113d6d189 | ||
|
|
fd9dac86b9 | ||
|
|
fe1f3bd4bb | ||
|
|
d950718110 | ||
|
|
4be903b9d5 | ||
|
|
8050644869 | ||
|
|
347c1986df | ||
|
|
eac4a8988b | ||
|
|
25137f29d2 | ||
|
|
4601fe74bb | ||
|
|
f0b54e9cbf | ||
|
|
fdb45c3624 | ||
|
|
f3b1ec0ed8 | ||
|
|
79510614b9 | ||
|
|
f8c9bc6812 | ||
|
|
85d35aab90 | ||
|
|
f5b09dbd10 | ||
|
|
57ea322fd6 | ||
|
|
c31aab5594 | ||
|
|
a5556e8c41 | ||
|
|
0ce2966c47 | ||
|
|
f2c04a13af | ||
|
|
60ba0de219 | ||
|
|
99e515604e | ||
|
|
84dfa60fc2 | ||
|
|
a753095f92 | ||
|
|
ce0ff2fed8 | ||
|
|
1c1deb5ee7 | ||
|
|
e28749b794 | ||
|
|
7566cc89ca | ||
|
|
8b76c09559 | ||
|
|
c60d7d3faf | ||
|
|
3eb3d1e27e | ||
|
|
3083c7d9e0 | ||
|
|
9184219976 | ||
|
|
90a3d302f3 | ||
|
|
02dd5f9d11 | ||
|
|
3685c92b52 | ||
|
|
e1a04c8b0b | ||
|
|
5a704b7974 | ||
|
|
2376d0a9c6 | ||
|
|
87e0c05ec0 | ||
|
|
8140b75086 | ||
|
|
1f32d5469e | ||
|
|
b09549439f | ||
|
|
e1b7a5b267 | ||
|
|
1ed420aeb7 | ||
|
|
301a23b1e0 | ||
|
|
e53bb51f15 | ||
|
|
4e6e8fed82 | ||
|
|
b2809ad631 | ||
|
|
37648b41ea | ||
|
|
fac183c2ee | ||
|
|
b113448e01 | ||
|
|
c585ba7791 | ||
|
|
afb6c65c48 | ||
|
|
527e91c9eb | ||
|
|
9e2ef87611 | ||
|
|
f2342c3273 | ||
|
|
347981792e | ||
|
|
032d2f2784 | ||
|
|
ddc1119a80 | ||
|
|
0fe6774f04 | ||
|
|
2a71e44ae8 | ||
|
|
1257f1ce85 | ||
|
|
07cd9f4b16 | ||
|
|
ed5ff1c9ce | ||
|
|
7ffc2db76e | ||
|
|
03067ca6d6 | ||
|
|
a69f1337d7 | ||
|
|
5e83c3350a | ||
|
|
f051d2d01e | ||
|
|
257340283b | ||
|
|
e769d77ec8 | ||
|
|
1923535918 | ||
|
|
dd3fc5620b | ||
|
|
7165258431 | ||
|
|
df9b367e0b | ||
|
|
ed1ae71f71 | ||
|
|
1c58bca454 | ||
|
|
c01be0644e | ||
|
|
66b9f6104c | ||
|
|
af4d2c4003 | ||
|
|
3b1a2f19a4 | ||
|
|
6b874786a8 | ||
|
|
f9d2560468 | ||
|
|
961034584a | ||
|
|
f6d11a59a3 | ||
|
|
53ee758378 | ||
|
|
c80c630810 | ||
|
|
13cd6e82ba | ||
|
|
f2966032d9 | ||
|
|
76503b52f5 | ||
|
|
aa24be8e9b | ||
|
|
5d7bb894d4 | ||
|
|
fcf559fa6b | ||
|
|
27963b5aed | ||
|
|
40d539c4aa | ||
|
|
d1433aaf7b | ||
|
|
8f4bf9a314 | ||
|
|
cca0f407f6 | ||
|
|
1e9e41754a | ||
|
|
38dc2d6e26 | ||
|
|
ea46b1c8c8 | ||
|
|
5846d7c4b4 | ||
|
|
214176ce2e | ||
|
|
ee4cb214e1 | ||
|
|
01cca9e8a6 | ||
|
|
7a23493e19 | ||
|
|
e109f069a8 | ||
|
|
82e667e402 | ||
|
|
c28feb2d1c | ||
|
|
8447a2d4f2 | ||
|
|
f9ebf1c399 | ||
|
|
286b27720a | ||
|
|
dc0e54c275 | ||
|
|
b710291d5e | ||
|
|
d84d5f38f5 | ||
|
|
9bea13438f | ||
|
|
2fc28f6005 | ||
|
|
bb07d6ec56 | ||
|
|
3cdfd04048 | ||
|
|
2120a258f9 | ||
|
|
2b5e49d215 | ||
|
|
b88bf9bdf2 | ||
|
|
df0f15d132 | ||
|
|
a6319bfb3d | ||
|
|
d6278cb3eb | ||
|
|
560da38687 | ||
|
|
83ba9d8776 | ||
|
|
ee776e6e3e | ||
|
|
3e52496b4e | ||
|
|
2659b96008 | ||
|
|
a8be84701b | ||
|
|
0c79aa1709 | ||
|
|
e57a19857f | ||
|
|
469dd05cd9 | ||
|
|
fb72db61bd | ||
|
|
c285e30ee0 | ||
|
|
789a327322 | ||
|
|
b8d2021599 | ||
|
|
36eae744af | ||
|
|
00df6ae52a | ||
|
|
023b65572e | ||
|
|
904e9b869c | ||
|
|
6f204b960d | ||
|
|
6217a51fa5 | ||
|
|
f1edb05c5c | ||
|
|
55bd27bb97 | ||
|
|
e2c9b601a6 | ||
|
|
238191660e | ||
|
|
0b175acc25 | ||
|
|
02865cbece | ||
|
|
a3e14bf579 | ||
|
|
1d502cbb54 | ||
|
|
4894b110b9 | ||
|
|
cefd0440a0 | ||
|
|
296bfb343e | ||
|
|
bc91f0d3ff | ||
|
|
aaa8215a6d | ||
|
|
bf0b37895d | ||
|
|
0810ed411d | ||
|
|
ff8fec542c | ||
|
|
8fb7308572 | ||
|
|
c9b7049532 | ||
|
|
da71332de1 | ||
|
|
a0de8dd9f9 | ||
|
|
e226f27041 | ||
|
|
804a04d9f8 | ||
|
|
3be06bb3b6 | ||
|
|
c7b618c246 | ||
|
|
55d990962f | ||
|
|
53e0a36539 | ||
|
|
ed7a5219bf | ||
|
|
8b49ccdc08 | ||
|
|
04fd3ade5f | ||
|
|
48985cd49d | ||
|
|
dd0707a8a5 | ||
|
|
b41ebcbbc8 | ||
|
|
991d2e3a57 | ||
|
|
7f4ac6782f | ||
|
|
7e7e30a82e | ||
|
|
08e92f12d3 | ||
|
|
d713ea6a76 | ||
|
|
0924020f24 | ||
|
|
9f10af3ba6 | ||
|
|
f754026cc5 | ||
|
|
321d98f4c1 | ||
|
|
58a49a8512 | ||
|
|
98bb9575b6 | ||
|
|
f10a135dea | ||
|
|
f300e524d1 | ||
|
|
87028c0a0b | ||
|
|
8ea23e6965 | ||
|
|
f9d8942814 | ||
|
|
b40df2f1e3 | ||
|
|
884cb0d9a4 | ||
|
|
ef1ccd4286 | ||
|
|
898abda373 | ||
|
|
e42c664a8c | ||
|
|
987bf47827 | ||
|
|
6201dd1d74 | ||
|
|
5ed17ce4e5 | ||
|
|
e301eca9c2 | ||
|
|
8a4ef015a2 | ||
|
|
67f3f3fdbb | ||
|
|
adc5b559cd | ||
|
|
bbaa637118 | ||
|
|
a3094b4d19 | ||
|
|
c3f937e113 | ||
|
|
04df327939 | ||
|
|
b1a0f46ade | ||
|
|
389e249862 | ||
|
|
cfcf9f6818 | ||
|
|
bcb8419f37 | ||
|
|
7d24bcf1dc | ||
|
|
8d0f7a2dc7 | ||
|
|
a7cb7beaa8 | ||
|
|
3c9b82dc04 | ||
|
|
9dba6d5371 | ||
|
|
a65bba0969 | ||
|
|
175e009152 | ||
|
|
897d17c8ed | ||
|
|
ca866cfa3a | ||
|
|
f6b2c0b2ba | ||
|
|
ea419c68ae | ||
|
|
40cf348d40 | ||
|
|
93ea759a71 | ||
|
|
3e50377eb8 | ||
|
|
3fbd1f8dc4 | ||
|
|
f03ce68513 | ||
|
|
50e2d542df | ||
|
|
e53e739d18 | ||
|
|
dfb7f7811f | ||
|
|
115824bbcf | ||
|
|
438de5760d | ||
|
|
3f765aedec | ||
|
|
96144fb10f | ||
|
|
cc34425712 | ||
|
|
9d68838893 | ||
|
|
6c68cebca0 | ||
|
|
b3e784262d | ||
|
|
2fdc22de71 | ||
|
|
77f0b0033f | ||
|
|
69da5abb88 | ||
|
|
a827e9a449 | ||
|
|
e74a29ae6a | ||
|
|
9b3d2f396e | ||
|
|
14cf7cc101 | ||
|
|
e5293c4d36 | ||
|
|
3afe21a4c3 | ||
|
|
bb50b69bb4 | ||
|
|
af7c030338 | ||
|
|
34b1eee876 | ||
|
|
c9cd1075d3 | ||
|
|
4fa04f0ff8 | ||
|
|
75f6466fd7 | ||
|
|
503ffd80fd | ||
|
|
c8ac64a571 | ||
|
|
bf81b902bd | ||
|
|
b636cdf9cc | ||
|
|
2d3b85825a | ||
|
|
a5a34f39e0 | ||
|
|
fe7e04f61b | ||
|
|
1a14720e35 | ||
|
|
18bf743ed2 | ||
|
|
f8d085a034 | ||
|
|
94bf3a136c | ||
|
|
9e8a8f3e71 | ||
|
|
45f9d93f3a | ||
|
|
44a566fdf3 | ||
|
|
d7f7770b7c | ||
|
|
df6b163505 | ||
|
|
51f88fff71 | ||
|
|
6b8db5abc6 | ||
|
|
37a0b07d56 |
3
.eslintignore
Normal file
3
.eslintignore
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules/*
|
||||
build/*
|
||||
lib/*
|
||||
120
.eslintrc.json
Normal file
120
.eslintrc.json
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"impliedStrict": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"indent": "off",
|
||||
"arrow-parens": [
|
||||
"off",
|
||||
"as-needed"
|
||||
],
|
||||
"brace-style": "off",
|
||||
"comma-spacing": "off",
|
||||
"space-infix-ops": "error",
|
||||
"comma-dangle": "off",
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"smart"
|
||||
],
|
||||
"import/order": "off",
|
||||
"no-eval": "warn",
|
||||
"no-new-wrappers": "warn",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-unsafe-finally": "warn",
|
||||
"no-var": "error",
|
||||
"spaced-comment": "error",
|
||||
"semi": "warn",
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
"selector": "ExportDefaultDeclaration",
|
||||
"message": "Default exports are not allowed"
|
||||
}
|
||||
],
|
||||
"no-throw-literal": "error",
|
||||
"key-spacing": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"array-bracket-spacing": "error",
|
||||
"space-in-parens": "error",
|
||||
"computed-property-spacing": "error",
|
||||
"prefer-const": ["error", {
|
||||
"destructuring": "all",
|
||||
"ignoreReadBeforeAssign": false
|
||||
}],
|
||||
"space-before-function-paren": "off",
|
||||
"func-call-spacing": "off",
|
||||
"no-multi-spaces": "error",
|
||||
"block-spacing": "error",
|
||||
"keyword-spacing": "off",
|
||||
"space-before-blocks": "error",
|
||||
"semi-spacing": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.ts", "**/*.tsx"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": ["tsconfig.json", "tsconfig.commonjs.json"],
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/class-name-casing": "off",
|
||||
"@typescript-eslint/indent": [
|
||||
"error",
|
||||
4
|
||||
],
|
||||
"@typescript-eslint/member-delimiter-style": [
|
||||
"off",
|
||||
{
|
||||
"multiline": {
|
||||
"delimiter": "none",
|
||||
"requireLast": true
|
||||
},
|
||||
"singleline": {
|
||||
"delimiter": "semi",
|
||||
"requireLast": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/prefer-namespace-keyword": "warn",
|
||||
"@typescript-eslint/quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/semi": [
|
||||
"off",
|
||||
null
|
||||
],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/brace-style": [
|
||||
"error",
|
||||
"1tbs", { "allowSingleLine": true }
|
||||
],
|
||||
"@typescript-eslint/comma-spacing": "error",
|
||||
"@typescript-eslint/space-before-function-paren": ["error", {
|
||||
"anonymous": "always",
|
||||
"named": "never",
|
||||
"asyncArrow": "always"
|
||||
}],
|
||||
"@typescript-eslint/func-call-spacing": ["error"],
|
||||
"@typescript-eslint/keyword-spacing": ["error"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
20
.github/workflows/node.yml
vendored
Normal file
20
.github/workflows/node.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
- run: npm ci
|
||||
- run: sudo apt-get install xvfb
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
- name: Test
|
||||
run: xvfb-run --auto-servernum npm run jest
|
||||
- name: Build
|
||||
run: npm run build
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,6 +5,9 @@ node_modules/
|
||||
debug.log
|
||||
npm-debug.log
|
||||
tsconfig.tsbuildinfo
|
||||
tsconfig.commonjs.tsbuildinfo
|
||||
|
||||
*.sublime-workspace
|
||||
.idea
|
||||
|
||||
.DS_Store
|
||||
1
.npmignore
Normal file
1
.npmignore
Normal file
@@ -0,0 +1 @@
|
||||
lib/tsconfig.commonjs.tsbuildinfo
|
||||
@@ -14,6 +14,5 @@ before_install:
|
||||
node_js:
|
||||
- "12"
|
||||
- "10"
|
||||
- "8"
|
||||
before_script:
|
||||
- export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start
|
||||
18
.vscode/extensions.json
vendored
Normal file
18
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"firsttris.vscode-jest-runner",
|
||||
"msjsdiag.debugger-for-chrome",
|
||||
"slevesque.shader",
|
||||
"stpn.vscode-graphql",
|
||||
"wayou.vscode-todo-highlight"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
|
||||
]
|
||||
}
|
||||
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Mol* Viewer",
|
||||
"url": "http://localhost:1338/build/viewer/index.html",
|
||||
"sourceMaps": true,
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -6,4 +6,7 @@
|
||||
"*.vert.ts": "glsl",
|
||||
"*.gql.ts": "graphql"
|
||||
},
|
||||
"eslint.options": {
|
||||
"ignorePattern": ["webpack.config.js", "scripts/*"],
|
||||
}
|
||||
}
|
||||
14
.vscode/tasks.json
vendored
14
.vscode/tasks.json
vendored
@@ -9,6 +9,20 @@
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build-tsc",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
222
CHANGELOG.md
Normal file
222
CHANGELOG.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file, following the suggestions of [Keep a CHANGELOG](http://keepachangelog.com/). This project adheres to [Semantic Versioning](http://semver.org/) for its most widely used - and defacto - public interfaces.
|
||||
|
||||
Note that since we don't clearly distinguish between a public and private interfaces there will be changes in non-major versions that are potentially breaking. If we make breaking changes to less used interfaces we will highlight it in here.
|
||||
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.0.0-dev.0] - 2021-11-28
|
||||
|
||||
- Add multiple lights support (with color, intensity, and direction parameters)
|
||||
- [Breaking] Add per-object material rendering properties
|
||||
- Add substance theme with per-group material rendering properties
|
||||
|
||||
## [v2.4.1] - 2021-11-28
|
||||
|
||||
- Fix: allow atoms in aromatic rings to do hydrogen bonds
|
||||
|
||||
## [v2.4.0] - 2021-11-25
|
||||
|
||||
- Fix secondary-structure property handling
|
||||
- StructureElement.Property was incorrectly resolving type & key
|
||||
- StructureSelectionQuery helpers 'helix' & 'beta' were not ensuring property availability
|
||||
- Re-enable VAO with better workaround (bind null elements buffer before deleting)
|
||||
- Add ``Representation.geometryVersion`` (increments whenever the geometry of any of its visuals changes)
|
||||
- Add support for grid-based smoothing of Overpaint and Transparency visual state for surfaces
|
||||
|
||||
## [v2.3.9] - 2021-11-20
|
||||
|
||||
- Workaround: switch off VAO support for now
|
||||
|
||||
## [v2.3.8] - 2021-11-20
|
||||
|
||||
- Fix double canvas context creation (in plugin context)
|
||||
- Fix unused vertex attribute handling (track which are used, disable the rest)
|
||||
- Workaround for VAO issue in Chrome 96 (can cause WebGL to crash on geometry updates)
|
||||
|
||||
## [v2.3.7] - 2021-11-15
|
||||
|
||||
- Added ``ViewerOptions.collapseRightPanel``
|
||||
- Added ``Viewer.loadTrajectory`` to support loading "composed" trajectories (e.g. from gro + xtc)
|
||||
- Fix: handle parent in Structure.remapModel
|
||||
- Add ``rounded`` and ``square`` helix profile options to Cartoon representation (in addition to the default ``elliptical``)
|
||||
|
||||
## [v2.3.6] - 2021-11-8
|
||||
|
||||
- Add additional measurement controls: orientation (box, axes, ellipsoid) & plane (best fit)
|
||||
- Improve aromatic bond visuals (add ``aromaticScale``, ``aromaticSpacing``, ``aromaticDashCount`` params)
|
||||
- [Breaking] Change ``adjustCylinderLength`` default to ``false`` (set to true for focus representation)
|
||||
- Fix marker highlight color overriding select color
|
||||
- CellPack extension update
|
||||
- add binary model support
|
||||
- add compartment (including membrane) geometry support
|
||||
- add latest mycoplasma model example
|
||||
- Prefer WebGL1 in Safari 15.1.
|
||||
|
||||
## [v2.3.5] - 2021-10-19
|
||||
|
||||
- Fix sequence viewer for PDB files with COMPND record and multichain entities.
|
||||
- Fix index pair bonds order assignment
|
||||
|
||||
## [v2.3.4] - 2021-10-12
|
||||
|
||||
- Fix pickScale not taken into account in line/point shader
|
||||
- Add pixel-scale, pick-scale & pick-padding GET params to Viewer app
|
||||
- Fix selecting bonds not adding their atoms in selection manager
|
||||
- Add ``preferAtoms`` option to SelectLoci/HighlightLoci behaviors
|
||||
- Make the implicit atoms of bond visuals pickable
|
||||
- Add ``preferAtomPixelPadding`` to Canvas3dInteractionHelper
|
||||
- Add points & crosses visuals to Line representation
|
||||
- Add ``pickPadding`` config option (look around in case target pixel is empty)
|
||||
- Add ``multipleBonds`` param to bond visuals with options: off, symmetric, offset
|
||||
- Fix ``argparse`` config in servers.
|
||||
|
||||
## [v2.3.3] - 2021-10-01
|
||||
|
||||
- Fix direct volume shader
|
||||
|
||||
## [v2.3.2] - 2021-10-01
|
||||
|
||||
- Prefer WebGL1 on iOS devices until WebGL2 support has stabilized.
|
||||
|
||||
## [v2.3.1] - 2021-09-28
|
||||
|
||||
- Add Charmm saccharide names
|
||||
- Treat missing occupancy column as occupancy of 1
|
||||
- Fix line shader not accounting for aspect ratio
|
||||
- [Breaking] Fix point repr & shader
|
||||
- Was unusable with ``wboit``
|
||||
- Replaced ``pointFilledCircle`` & ``pointEdgeBleach`` params by ``pointStyle`` (square, circle, fuzzy)
|
||||
- Set ``pointSizeAttenuation`` to false by default
|
||||
- Set ``sizeTheme`` to ``uniform`` by default
|
||||
- Add ``markerPriority`` option to Renderer (useful in combination with edges of marking pass)
|
||||
- Add support support for ``chem_comp_bond`` and ``struct_conn`` categories (fixes ModelServer behavior where these categories should have been present)
|
||||
- Model and VolumeServer: fix argparse config
|
||||
|
||||
## [v2.3.0] - 2021-09-06
|
||||
|
||||
- Take include/exclude flags into account when displaying aromatic bonds
|
||||
- Improve marking performance
|
||||
- Avoid unnecessary draw calls/ui updates when marking
|
||||
- Check if loci is superset of visual
|
||||
- Check if loci overlaps with unit visual
|
||||
- Ensure ``Interval`` is used for ranges instead of ``SortedArray``
|
||||
- Add uniform marker type
|
||||
- Special case for reversing previous mark
|
||||
- Add optional marking pass
|
||||
- Outlines visible and hidden parts of highlighted/selected groups
|
||||
- Add highlightStrength/selectStrength renderer params
|
||||
|
||||
## [v2.2.3] - 2021-08-25
|
||||
|
||||
- Add ``invertCantorPairing`` helper function
|
||||
- Add ``Mesh`` processing helper ``.smoothEdges``
|
||||
- Smooth border of molecular-surface with ``includeParent`` enabled
|
||||
- Hide ``includeParent`` option from gaussian-surface visuals (not particularly useful)
|
||||
- Improved ``StructureElement.Loci.size`` performance (for marking large cellpack models)
|
||||
- Fix new ``TransformData`` issues (camera/bounding helper not showing up)
|
||||
- Improve marking performance (avoid superfluous calls to ``StructureElement.Loci.isWholeStructure``)
|
||||
|
||||
## [v2.2.2] - 2021-08-11
|
||||
|
||||
- Fix ``TransformData`` issues [#133](https://github.com/molstar/molstar/issues/133)
|
||||
- Fix ``mol-script`` query compiler const expression recognition.
|
||||
|
||||
## [v2.2.1] - 2021-08-02
|
||||
|
||||
- Add surrounding atoms (5 Angstrom) structure selection query
|
||||
- [Breaking] Add maxDistance prop to ``IndexPairBonds``
|
||||
- Fix coordinateSystem not handled in ``Structure.asParent``
|
||||
- Add ``dynamicBonds`` to ``Structure`` props (force re-calc on model change)
|
||||
- Expose as optional param in root structure transform helper
|
||||
- Add overpaint support to geometry exporters
|
||||
- ``InputObserver`` improvements
|
||||
- normalize wheel speed across browsers/platforms
|
||||
- support Safari gestures (used by ``TrackballControls``)
|
||||
- ``PinchInput.fractionDelta`` and use it in ``TrackballControls``
|
||||
|
||||
## [v2.2.0] - 2021-07-31
|
||||
|
||||
- Add ``tubularHelices`` parameter to Cartoon representation
|
||||
- Add ``SdfFormat`` and update SDF parser to be able to parse data headers according to spec (hopefully :)) #230
|
||||
- Fix mononucleotides detected as polymer components (#229)
|
||||
- Set default outline scale back to 1
|
||||
- Improved DCD reader cell angle handling (interpret near 0 angles as 90 deg)
|
||||
- Handle more residue/atom names commonly used in force-fields
|
||||
- Add USDZ support to ``geo-export`` extension.
|
||||
- Fix ``includeParent`` support for multi-instance bond visuals.
|
||||
- Add ``operator`` Loci granularity, selecting everything with the same operator name.
|
||||
- Prefer ``_label_seq_id`` fields in secondary structure assignment.
|
||||
- Support new EMDB API (https://www.ebi.ac.uk/emdb/api/entry/map/[EMBD-ID]) for EM volume contour levels.
|
||||
- ``Canvas3D`` tweaks:
|
||||
- Update ``forceDraw`` logic.
|
||||
- Ensure the scene is re-rendered when viewport size changes.
|
||||
- Support ``noDraw`` mode in ``PluginAnimationLoop``.
|
||||
|
||||
## [v2.1.0] - 2021-07-05
|
||||
|
||||
- Add parameter for to display aromatic bonds as dashes next to solid cylinder/line.
|
||||
- Add backbone representation
|
||||
- Fix outline in orthographic mode and set default scale to 2.
|
||||
|
||||
## [v2.0.7] - 2021-06-23
|
||||
|
||||
- Add ability to specify ``volumeIndex`` in ``Viewer.loadVolumeFromUrl`` to better support Volume Server inputs.
|
||||
- Support in-place reordering for trajectory ``Frame.x/y/z`` arrays for better memory efficiency.
|
||||
- Fixed text CIF encoder edge cases (most notably single whitespace not being escaped).
|
||||
|
||||
## [v2.0.6] - 2021-06-01
|
||||
|
||||
- Add glTF (GLB) and STL support to ``geo-export`` extension.
|
||||
- Protein crosslink improvements
|
||||
- Change O-S bond distance to allow for NOS bridges (doi:10.1038/s41586-021-03513-3)
|
||||
- Added NOS-bridges query & improved disulfide-bridges query
|
||||
- Fix #178: ``IndexPairBonds`` for non-single residue structures (bug due to atom reordering).
|
||||
- Add volumetric color smoothing for MolecularSurface and GaussianSurface representations (#173)
|
||||
- Fix nested 3d grid lookup that caused results being overwritten in non-covalent interactions computation.
|
||||
- Basic implementation of ``BestDatabaseSequenceMapping`` (parse from CIF, color theme, superposition).
|
||||
- Add atom id ranges support to Selection UI.
|
||||
|
||||
## [v2.0.5] - 2021-04-26
|
||||
|
||||
- Ability to pass ``Canvas3DContext`` to ``PluginContext.fromCanvas``.
|
||||
- Relative frame support for ``Canvas3D`` viewport.
|
||||
- Fix bug in screenshot copy UI.
|
||||
- Add ability to select residues from a list of identifiers to the Selection UI.
|
||||
- Fix SSAO bugs when used with ``Canvas3D`` viewport.
|
||||
- Support for full pausing (no draw) rendering: ``Canvas3D.pause(true)``.
|
||||
- Add ``MeshBuilder.addMesh``.
|
||||
- Add ``Torus`` primitive.
|
||||
- Lazy volume loading support.
|
||||
- [Breaking] ``Viewer.loadVolumeFromUrl`` signature change.
|
||||
- ``loadVolumeFromUrl(url, format, isBinary, isovalues, entryId)`` => ``loadVolumeFromUrl({ url, format, isBinary }, isovalues, { entryId, isLazy })``
|
||||
- Add ``TextureMesh`` support to ``geo-export`` extension.
|
||||
|
||||
## [v2.0.4] - 2021-04-20
|
||||
|
||||
- [WIP] Mesh export extension
|
||||
- ``Structure.eachAtomicHierarchyElement`` (#161)
|
||||
- Fixed reading multi-line values in SDF format
|
||||
- Fixed Measurements UI labels (#166)
|
||||
|
||||
## [v2.0.3] - 2021-04-09
|
||||
|
||||
- Add support for ``ColorTheme.palette`` designed for providing gradient-like coloring.
|
||||
- [Breaking] The ``zip`` function is now asynchronous and expects a ``RuntimeContext``. Also added ``Zip()`` returning a ``Task``.
|
||||
- [Breaking] Add ``CubeGridFormat`` in ``alpha-orbitals`` extension.
|
||||
|
||||
## [v2.0.2] - 2021-03-29
|
||||
|
||||
- Add ``Canvas3D.getRenderObjects``.
|
||||
- [WIP] Animate state interpolating, including model trajectories
|
||||
- Recognise MSE, SEP, TPO, PTR and PCA as non-standard amino-acids.
|
||||
- Fix VolumeFromDensityServerCif transform label
|
||||
|
||||
## [v2.0.1] - 2021-03-23
|
||||
|
||||
- Exclude tsconfig.commonjs.tsbuildinfo from npm bundle
|
||||
|
||||
## [v2.0.0] - 2021-03-23
|
||||
|
||||
Too many changes to list as this is the start of the changelog... Notably, default exports are now forbidden.
|
||||
80
README.md
80
README.md
@@ -5,40 +5,42 @@
|
||||
|
||||
# Mol*
|
||||
|
||||
The goal of **Mol\*** (*/'mol-star/*) is to provide a technology stack that will serve as basis for the next-generation data delivery and analysis tools for macromolecular structure data. This is a collaboration between PDBe and RCSB PDB teams and the development will be open source and available to anyone who wants to use it for developing visualisation tools for macromolecular structure data available from [PDB](https://www.wwpdb.org/) and other institutions.
|
||||
The goal of **Mol\*** (*/'mol-star/*) is to provide a technology stack that serves as a basis for the next-generation data delivery and analysis tools for (not only) macromolecular structure data. Mol* development was jointly initiated by PDBe and RCSB PDB to combine and build on the strengths of [LiteMol](https://litemol.org) (developed by PDBe) and [NGL](https://nglviewer.org) (developed by RCSB PDB) viewers.
|
||||
|
||||
This particular project is the implementation of this technology (still under development).
|
||||
When using Mol*, please cite:
|
||||
|
||||
*If you are looking for the "MOLeculAR structure annoTator", that package is now available on NPM as [MolArt](https://www.npmjs.com/package/molart).*
|
||||
David Sehnal, Sebastian Bittrich, Mandar Deshpande, Radka Svobodová, Karel Berka, Václav Bazgier, Sameer Velankar, Stephen K Burley, Jaroslav Koča, Alexander S Rose: [Mol* Viewer: modern web app for 3D visualization and analysis of large biomolecular structures](https://doi.org/10.1093/nar/gkab314), *Nucleic Acids Research*, 2021; https://doi.org/10.1093/nar/gkab314.
|
||||
|
||||
## Project Overview
|
||||
## Project Structure Overview
|
||||
|
||||
The core of Mol* currently consists of these modules (see under `src/`):
|
||||
The core of Mol* consists of these modules (see under `src/`):
|
||||
|
||||
- `mol-task` Computation abstraction with progress tracking and cancellation support.
|
||||
- `mol-data` Collections (integer based sets, interface to columns/tables, etc.)
|
||||
- `mol-data` Collections (integer-based sets, interface to columns/tables, etc.)
|
||||
- `mol-math` Math related (loosely) algorithms and data structures.
|
||||
- `mol-io` Parsing library. Each format is parsed into an interface that corresponds to the data stored by it. Support for common coordinate, experimental/map, and annotation data formats.
|
||||
- `mol-model` Data structures and algorithms (such as querying) for representing molecular data (including coordinate, experimental/map, and annotation data).
|
||||
- `mol-model-formats` Data format parsers for `mol-model`.
|
||||
- `mol-model-props` Common "custom properties".
|
||||
- `mol-script` A scriting language for creating representations/scenes and querying (includes the [MolQL query language](https://molql.github.io)).
|
||||
- `mol-script` A scripting language for creating representations/scenes and querying (includes the [MolQL query language](https://molql.github.io)).
|
||||
- `mol-geo` Creating (molecular) geometries.
|
||||
- `mol-theme` Theming for structure, volume and shape representations.
|
||||
- `mol-repr` Molecular representations for structures, volumes and shapes.
|
||||
- `mol-gl` A wrapper around WebGL.
|
||||
- `mol-canvas3d` A low level 3d view component. Uses `mol-geo` to generate geometries.
|
||||
- `mol-canvas3d` A low-level 3d view component. Uses `mol-geo` to generate geometries.
|
||||
- `mol-state` State representation tree with state saving and automatic updates.
|
||||
- `mol-app` Components for builduing UIs.
|
||||
- `mol-plugin` Allow to define modular Mol* plugin instances utilizing `mol-state` and `mol-canvas3d`.
|
||||
- `mol-plugin-state` State transformations, builders, and managers.
|
||||
- `mol-plugin-ui` React-based user interface for the Mol* plugin. Some components of the UI are usable outside the main plugin and can be integrated into 3rd party solutions.
|
||||
- `mol-util` Useful things that do not fit elsewhere.
|
||||
|
||||
Moreover, the project contains the imlementation of `servers`, including
|
||||
Moreover, the project contains the implementation of `servers`, including
|
||||
|
||||
- `servers/model` A tool for accessing coordinate and annotation data of molecular structures.
|
||||
- `servers/volume` A tool for accessing volumetric experimental data related to molecular structures.
|
||||
- `servers/plugin-state` A basic server to store Mol* Plugin states.
|
||||
|
||||
The project also contains performance tests (`perf-tests`), `examples`, and basic proof of concept `apps` (CIF to BinaryCIF converter and JSON domain annotation to CIF converter).
|
||||
The project also contains performance tests (`perf-tests`), `examples`, and `cli` apps (CIF to BinaryCIF converter and JSON domain annotation to CIF converter).
|
||||
|
||||
## Previous Work
|
||||
This project builds on experience from previous solutions:
|
||||
@@ -59,9 +61,13 @@ This project builds on experience from previous solutions:
|
||||
### Build automatically on file save:
|
||||
npm run watch
|
||||
|
||||
If working on just the viewer, ``npm run watch-viewer`` will provide shorter compile times.
|
||||
|
||||
### Build with debug mode enabled:
|
||||
DEBUG=molstar npm run watch
|
||||
|
||||
Debug/production mode in browsers can be turned on/off during runtime by calling ``setMolStarDebugMode(true/false, true/false)`` from the dev console.
|
||||
|
||||
### Build for production:
|
||||
NODE_ENV=production npm run build
|
||||
|
||||
@@ -82,20 +88,29 @@ and navigate to `build/viewer`
|
||||
|
||||
### Code generation
|
||||
**CIF schemas**
|
||||
Install CIFTools `npm install ciftools -g`
|
||||
|
||||
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/mmcif.ts -p mmCIF
|
||||
cifschema -mip ../../../../mol-data-o src/mol-io/reader/cif/schema/ccd.ts -p CCD
|
||||
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/bird.ts -p BIRD
|
||||
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/mmcif.ts -p mmCIF
|
||||
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/ccd.ts -p CCD
|
||||
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/bird.ts -p BIRD
|
||||
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/cif-core.ts -p CifCore -aa
|
||||
|
||||
**Lipid names**
|
||||
|
||||
node lib/commonjs/cli/lipid-params -o src/mol-model/structure/model/types/lipids.ts
|
||||
|
||||
**Ion names**
|
||||
|
||||
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-ions.js src/mol-model/structure/model/types/ions.ts
|
||||
|
||||
|
||||
**GraphQL schemas**
|
||||
|
||||
node data/rcsb-graphql/codegen.js
|
||||
node node_modules//@graphql-codegen/cli/bin -c src/extensions/rcsb/graphql/codegen.yml
|
||||
|
||||
### Other scripts
|
||||
**Create chem comp bond table**
|
||||
|
||||
export NODE_PATH="lib"; node --max-old-space-size=8192 build/src/apps/chem-comp-bond/create-table.js build/data/ccb.bcif -b
|
||||
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-table.js build/data/ccb.bcif -b
|
||||
|
||||
**Test model server**
|
||||
|
||||
@@ -107,22 +122,26 @@ Install CIFTools `npm install ciftools -g`
|
||||
|
||||
**Convert any CIF to BinaryCIF**
|
||||
|
||||
node build/model-server/preprocess -i file.cif -ob file.bcif
|
||||
node lib/commonjs/servers/model/preprocess -i file.cif -ob file.bcif
|
||||
|
||||
To see all available commands, use ``node build/model-server/preprocess -h``.
|
||||
To see all available commands, use ``node lib/commonjs/servers/model/preprocess -h``.
|
||||
|
||||
Or
|
||||
|
||||
node lib/commonjs/cli/cif2bcif
|
||||
|
||||
## Development
|
||||
|
||||
### Intallation
|
||||
### Installation
|
||||
|
||||
If node complains about a missine acorn peer dependency, run the following commands
|
||||
If node complains about a missing acorn peer dependency, run the following commands
|
||||
|
||||
npm update acorn --depth 20
|
||||
npm dedupe
|
||||
|
||||
### Editor
|
||||
|
||||
To get syntax highlighting for shader and graphql files add the following to Visual Code's settings files and make sure relevant extanesions are installed in the editor.
|
||||
To get syntax highlighting for shader and graphql files add the following to Visual Code's settings files and make sure relevant extensions are installed in the editor.
|
||||
|
||||
"files.associations": {
|
||||
"*.glsl.ts": "glsl",
|
||||
@@ -133,22 +152,25 @@ To get syntax highlighting for shader and graphql files add the following to Vis
|
||||
|
||||
## Publish
|
||||
|
||||
## Prerelease
|
||||
npm version prerelease # asumes the current version ends with '-dev.X'
|
||||
### Prerelease
|
||||
npm version prerelease # assumes the current version ends with '-dev.X'
|
||||
npm publish --tag next
|
||||
|
||||
## Release
|
||||
### Release
|
||||
npm version 0.X.0 # provide valid semver string
|
||||
npm publish
|
||||
|
||||
## Deploy
|
||||
npm run test
|
||||
npm run build
|
||||
node ./scripts/deploy.js # currently updates the viewer on molstar.org/viewer
|
||||
|
||||
## Contributing
|
||||
Just open an issue or make a pull request. All contributions are welcome.
|
||||
|
||||
## Roadmap
|
||||
Continually develop this prototype project. As individual modules become stable, make them into standalone libraries.
|
||||
|
||||
## Funding
|
||||
Funding sources include but are not limited to:
|
||||
* [RCSB PDB](https://www.rcsb.org) funding by a grant [DBI-1338415; PI: SK Burley] from the NSF, the NIH, and the US DoE
|
||||
* [PDBe, EMBL-EBI](https://pdbe.org)
|
||||
* [CEITEC](https://www.ceitec.eu/)
|
||||
* [CEITEC](https://www.ceitec.eu/)
|
||||
* [EntosAI](https://www.entos.ai)
|
||||
|
||||
88
data/cif-field-names/bird-field-names.csv
Normal file
88
data/cif-field-names/bird-field-names.csv
Normal file
@@ -0,0 +1,88 @@
|
||||
pdbx_reference_molecule.prd_id
|
||||
pdbx_reference_molecule.name
|
||||
pdbx_reference_molecule.represent_as
|
||||
pdbx_reference_molecule.type
|
||||
pdbx_reference_molecule.type_evidence_code
|
||||
pdbx_reference_molecule.class
|
||||
pdbx_reference_molecule.class_evidence_code
|
||||
pdbx_reference_molecule.formula
|
||||
pdbx_reference_molecule.chem_comp_id
|
||||
pdbx_reference_molecule.formula_weight
|
||||
pdbx_reference_molecule.release_status
|
||||
pdbx_reference_molecule.replaces
|
||||
pdbx_reference_molecule.replaced_by
|
||||
pdbx_reference_molecule.compound_details
|
||||
pdbx_reference_molecule.description
|
||||
pdbx_reference_molecule.representative_PDB_id_code
|
||||
|
||||
pdbx_reference_entity_list.prd_id
|
||||
pdbx_reference_entity_list.ref_entity_id
|
||||
pdbx_reference_entity_list.component_id
|
||||
pdbx_reference_entity_list.type
|
||||
pdbx_reference_entity_list.details
|
||||
|
||||
pdbx_reference_entity_nonpoly.prd_id
|
||||
pdbx_reference_entity_nonpoly.ref_entity_id
|
||||
pdbx_reference_entity_nonpoly.name
|
||||
pdbx_reference_entity_nonpoly.chem_comp_id
|
||||
|
||||
pdbx_reference_entity_link.prd_id
|
||||
pdbx_reference_entity_link.link_id
|
||||
pdbx_reference_entity_link.link_class
|
||||
pdbx_reference_entity_link.ref_entity_id_1
|
||||
pdbx_reference_entity_link.entity_seq_num_1
|
||||
pdbx_reference_entity_link.comp_id_1
|
||||
pdbx_reference_entity_link.atom_id_1
|
||||
pdbx_reference_entity_link.ref_entity_id_2
|
||||
pdbx_reference_entity_link.entity_seq_num_2
|
||||
pdbx_reference_entity_link.comp_id_2
|
||||
pdbx_reference_entity_link.atom_id_2
|
||||
pdbx_reference_entity_link.value_order
|
||||
pdbx_reference_entity_link.component_1
|
||||
pdbx_reference_entity_link.component_2
|
||||
pdbx_reference_entity_link.details
|
||||
|
||||
pdbx_reference_entity_poly_link.prd_id
|
||||
pdbx_reference_entity_poly_link.ref_entity_id
|
||||
pdbx_reference_entity_poly_link.link_id
|
||||
pdbx_reference_entity_poly_link.atom_id_1
|
||||
pdbx_reference_entity_poly_link.comp_id_1
|
||||
pdbx_reference_entity_poly_link.entity_seq_num_1
|
||||
pdbx_reference_entity_poly_link.atom_id_2
|
||||
pdbx_reference_entity_poly_link.comp_id_2
|
||||
pdbx_reference_entity_poly_link.entity_seq_num_2
|
||||
pdbx_reference_entity_poly_link.value_order
|
||||
pdbx_reference_entity_poly_link.component_id
|
||||
|
||||
pdbx_reference_entity_poly.prd_id
|
||||
pdbx_reference_entity_poly.ref_entity_id
|
||||
pdbx_reference_entity_poly.db_code
|
||||
pdbx_reference_entity_poly.db_name
|
||||
pdbx_reference_entity_poly.type
|
||||
|
||||
pdbx_reference_entity_sequence.prd_id
|
||||
pdbx_reference_entity_sequence.ref_entity_id
|
||||
pdbx_reference_entity_sequence.type
|
||||
pdbx_reference_entity_sequence.NRP_flag
|
||||
pdbx_reference_entity_sequence.one_letter_codes
|
||||
|
||||
pdbx_reference_entity_poly_seq.prd_id
|
||||
pdbx_reference_entity_poly_seq.ref_entity_id
|
||||
pdbx_reference_entity_poly_seq.num
|
||||
pdbx_reference_entity_poly_seq.mon_id
|
||||
pdbx_reference_entity_poly_seq.parent_mon_id
|
||||
pdbx_reference_entity_poly_seq.hetero
|
||||
pdbx_reference_entity_poly_seq.observed
|
||||
|
||||
pdbx_reference_entity_src_nat.prd_id
|
||||
pdbx_reference_entity_src_nat.ref_entity_id
|
||||
pdbx_reference_entity_src_nat.ordinal
|
||||
pdbx_reference_entity_src_nat.taxid
|
||||
pdbx_reference_entity_src_nat.organism_scientific
|
||||
pdbx_reference_entity_src_nat.db_code
|
||||
pdbx_reference_entity_src_nat.db_name
|
||||
|
||||
pdbx_prd_audit.prd_id
|
||||
pdbx_prd_audit.date
|
||||
pdbx_prd_audit.processing_site
|
||||
pdbx_prd_audit.action_type
|
||||
|
60
data/cif-field-names/ccd-field-names.csv
Normal file
60
data/cif-field-names/ccd-field-names.csv
Normal file
@@ -0,0 +1,60 @@
|
||||
chem_comp.id
|
||||
chem_comp.name
|
||||
chem_comp.type
|
||||
chem_comp.pdbx_type
|
||||
chem_comp.formula
|
||||
chem_comp.mon_nstd_parent_comp_id
|
||||
chem_comp.pdbx_synonyms
|
||||
chem_comp.pdbx_formal_charge
|
||||
chem_comp.pdbx_initial_date
|
||||
chem_comp.pdbx_modified_date
|
||||
chem_comp.pdbx_ambiguous_flag
|
||||
chem_comp.pdbx_release_status
|
||||
chem_comp.pdbx_replaced_by
|
||||
chem_comp.pdbx_replaces
|
||||
chem_comp.formula_weight
|
||||
chem_comp.one_letter_code
|
||||
chem_comp.three_letter_code
|
||||
chem_comp.pdbx_model_coordinates_details
|
||||
chem_comp.pdbx_model_coordinates_missing_flag
|
||||
chem_comp.pdbx_ideal_coordinates_details
|
||||
chem_comp.pdbx_ideal_coordinates_missing_flag
|
||||
chem_comp.pdbx_model_coordinates_db_code
|
||||
chem_comp.pdbx_processing_site
|
||||
|
||||
chem_comp_atom.comp_id
|
||||
chem_comp_atom.atom_id
|
||||
chem_comp_atom.alt_atom_id
|
||||
chem_comp_atom.type_symbol
|
||||
chem_comp_atom.charge
|
||||
chem_comp_atom.pdbx_align
|
||||
chem_comp_atom.pdbx_aromatic_flag
|
||||
chem_comp_atom.pdbx_leaving_atom_flag
|
||||
chem_comp_atom.pdbx_stereo_config
|
||||
chem_comp_atom.model_Cartn_x
|
||||
chem_comp_atom.model_Cartn_y
|
||||
chem_comp_atom.model_Cartn_z
|
||||
chem_comp_atom.pdbx_model_Cartn_x_ideal
|
||||
chem_comp_atom.pdbx_model_Cartn_y_ideal
|
||||
chem_comp_atom.pdbx_model_Cartn_z_ideal
|
||||
chem_comp_atom.pdbx_ordinal
|
||||
|
||||
chem_comp_bond.comp_id
|
||||
chem_comp_bond.atom_id_1
|
||||
chem_comp_bond.atom_id_2
|
||||
chem_comp_bond.value_order
|
||||
chem_comp_bond.pdbx_aromatic_flag
|
||||
chem_comp_bond.pdbx_stereo_config
|
||||
chem_comp_bond.pdbx_ordinal
|
||||
|
||||
pdbx_chem_comp_descriptor.comp_id
|
||||
pdbx_chem_comp_descriptor.type
|
||||
pdbx_chem_comp_descriptor.program
|
||||
pdbx_chem_comp_descriptor.program_version
|
||||
pdbx_chem_comp_descriptor.descriptor
|
||||
|
||||
pdbx_chem_comp_identifier.comp_id
|
||||
pdbx_chem_comp_identifier.type
|
||||
pdbx_chem_comp_identifier.program
|
||||
pdbx_chem_comp_identifier.program_version
|
||||
pdbx_chem_comp_identifier.identifier
|
||||
|
69
data/cif-field-names/cif-core-field-names.csv
Normal file
69
data/cif-field-names/cif-core-field-names.csv
Normal file
@@ -0,0 +1,69 @@
|
||||
audit.block_doi
|
||||
|
||||
database_code.depnum_ccdc_archive
|
||||
database_code.depnum_ccdc_fiz
|
||||
database_code.icsd
|
||||
database_code.mdf
|
||||
database_code.nbs
|
||||
database_code.csd
|
||||
database_code.cod
|
||||
|
||||
chemical.name_systematic
|
||||
chemical.name_common
|
||||
chemical.melting_point
|
||||
|
||||
chemical_formula.moiety
|
||||
chemical_formula.sum
|
||||
chemical_formula.weight
|
||||
|
||||
atom_type.symbol
|
||||
atom_type.description
|
||||
|
||||
atom_type_scat.dispersion_real
|
||||
atom_type_scat.dispersion_imag
|
||||
atom_type_scat.source
|
||||
|
||||
space_group.crystal_system
|
||||
space_group.name_h-m_full
|
||||
space_group.it_number
|
||||
space_group_symop.operation_xyz
|
||||
|
||||
cell.length_a
|
||||
cell.length_b
|
||||
cell.length_c
|
||||
cell.angle_alpha
|
||||
cell.angle_beta
|
||||
cell.angle_gamma
|
||||
cell.volume
|
||||
cell.formula_units_z
|
||||
|
||||
atom_site.label
|
||||
atom_site.type_symbol
|
||||
atom_site.fract_x
|
||||
atom_site.fract_y
|
||||
atom_site.fract_z
|
||||
atom_site.u_iso_or_equiv
|
||||
atom_site.adp_type
|
||||
atom_site.occupancy
|
||||
atom_site.calc_flag
|
||||
atom_site.refinement_flags
|
||||
atom_site.disorder_assembly
|
||||
atom_site.disorder_group
|
||||
atom_site.site_symmetry_multiplicity
|
||||
|
||||
atom_site_aniso.label
|
||||
atom_site_aniso.u
|
||||
atom_site_aniso.u_11
|
||||
atom_site_aniso.u_22
|
||||
atom_site_aniso.u_33
|
||||
atom_site_aniso.u_23
|
||||
atom_site_aniso.u_13
|
||||
atom_site_aniso.u_12
|
||||
|
||||
geom_bond.atom_site_label_1
|
||||
geom_bond.atom_site_label_2
|
||||
geom_bond.distance
|
||||
geom_bond.site_symmetry_1
|
||||
geom_bond.site_symmetry_2
|
||||
geom_bond.publ_flag
|
||||
geom_bond.valence
|
||||
|
805
data/cif-field-names/mmcif-field-names.csv
Normal file
805
data/cif-field-names/mmcif-field-names.csv
Normal file
@@ -0,0 +1,805 @@
|
||||
atom_sites.entry_id
|
||||
atom_sites.fract_transf_matrix
|
||||
atom_sites.fract_transf_vector
|
||||
|
||||
atom_site.group_PDB
|
||||
atom_site.id
|
||||
atom_site.type_symbol
|
||||
atom_site.label_atom_id
|
||||
atom_site.label_alt_id
|
||||
atom_site.label_comp_id
|
||||
atom_site.label_asym_id
|
||||
atom_site.label_entity_id
|
||||
atom_site.label_seq_id
|
||||
atom_site.pdbx_PDB_ins_code
|
||||
atom_site.pdbx_formal_charge
|
||||
atom_site.Cartn_x
|
||||
atom_site.Cartn_y
|
||||
atom_site.Cartn_z
|
||||
atom_site.occupancy
|
||||
atom_site.B_iso_or_equiv
|
||||
atom_site.auth_atom_id
|
||||
atom_site.auth_comp_id
|
||||
atom_site.auth_asym_id
|
||||
atom_site.auth_seq_id
|
||||
atom_site.pdbx_PDB_model_num
|
||||
atom_site.ihm_model_id
|
||||
|
||||
atom_site_anisotrop.id
|
||||
atom_site_anisotrop.U
|
||||
atom_site_anisotrop.U_esd
|
||||
atom_site_anisotrop.pdbx_PDB_ins_code
|
||||
atom_site_anisotrop.pdbx_auth_asym_id
|
||||
atom_site_anisotrop.pdbx_auth_atom_id
|
||||
atom_site_anisotrop.pdbx_auth_comp_id
|
||||
atom_site_anisotrop.pdbx_auth_seq_id
|
||||
atom_site_anisotrop.pdbx_label_alt_id
|
||||
atom_site_anisotrop.pdbx_label_asym_id
|
||||
atom_site_anisotrop.pdbx_label_atom_id
|
||||
atom_site_anisotrop.pdbx_label_comp_id
|
||||
atom_site_anisotrop.pdbx_label_seq_id
|
||||
atom_site_anisotrop.type_symbol
|
||||
|
||||
chem_comp.id
|
||||
chem_comp.type
|
||||
chem_comp.mon_nstd_flag
|
||||
chem_comp.name
|
||||
chem_comp.pdbx_synonyms
|
||||
chem_comp.formula
|
||||
chem_comp.formula_weight
|
||||
|
||||
chem_comp_bond.comp_id
|
||||
chem_comp_bond.pdbx_stereo_config
|
||||
chem_comp_bond.pdbx_ordinal
|
||||
chem_comp_bond.pdbx_aromatic_flag
|
||||
chem_comp_bond.atom_id_1
|
||||
chem_comp_bond.atom_id_2
|
||||
chem_comp_bond.value_order
|
||||
|
||||
pdbx_chem_comp_identifier.comp_id
|
||||
pdbx_chem_comp_identifier.type
|
||||
pdbx_chem_comp_identifier.program
|
||||
pdbx_chem_comp_identifier.program_version
|
||||
pdbx_chem_comp_identifier.identifier
|
||||
|
||||
pdbx_chem_comp_related.comp_id
|
||||
pdbx_chem_comp_related.related_comp_id
|
||||
pdbx_chem_comp_related.relationship_type
|
||||
pdbx_chem_comp_related.details
|
||||
|
||||
pdbx_chem_comp_synonyms.comp_id
|
||||
pdbx_chem_comp_synonyms.name
|
||||
pdbx_chem_comp_synonyms.provenance
|
||||
|
||||
cell.entry_id
|
||||
cell.length_a
|
||||
cell.length_b
|
||||
cell.length_c
|
||||
cell.angle_alpha
|
||||
cell.angle_beta
|
||||
cell.angle_gamma
|
||||
cell.Z_PDB
|
||||
cell.pdbx_unique_axis
|
||||
|
||||
pdbx_database_related.db_name
|
||||
pdbx_database_related.details
|
||||
pdbx_database_related.db_id
|
||||
pdbx_database_related.content_type
|
||||
|
||||
pdbx_database_status.status_code
|
||||
pdbx_database_status.status_code_sf
|
||||
pdbx_database_status.status_code_mr
|
||||
pdbx_database_status.entry_id
|
||||
pdbx_database_status.recvd_initial_deposition_date
|
||||
pdbx_database_status.SG_entry
|
||||
pdbx_database_status.deposit_site
|
||||
pdbx_database_status.process_site
|
||||
pdbx_database_status.status_code_cs
|
||||
pdbx_database_status.methods_development_category
|
||||
pdbx_database_status.pdb_format_compatible
|
||||
|
||||
entity.id
|
||||
entity.type
|
||||
entity.src_method
|
||||
entity.pdbx_description
|
||||
entity.formula_weight
|
||||
entity.pdbx_number_of_molecules
|
||||
entity.details
|
||||
entity.pdbx_mutation
|
||||
entity.pdbx_fragment
|
||||
entity.pdbx_ec
|
||||
|
||||
entity_poly.entity_id
|
||||
entity_poly.type
|
||||
entity_poly.nstd_linkage
|
||||
entity_poly.nstd_monomer
|
||||
entity_poly.pdbx_seq_one_letter_code
|
||||
entity_poly.pdbx_seq_one_letter_code_can
|
||||
entity_poly.pdbx_strand_id
|
||||
entity_poly.pdbx_target_identifier
|
||||
|
||||
entity_poly_seq.entity_id
|
||||
entity_poly_seq.num
|
||||
entity_poly_seq.mon_id
|
||||
entity_poly_seq.hetero
|
||||
|
||||
entity_src_gen.entity_id
|
||||
entity_src_gen.pdbx_src_id
|
||||
entity_src_gen.pdbx_beg_seq_num
|
||||
entity_src_gen.pdbx_end_seq_num
|
||||
entity_src_gen.pdbx_gene_src_gene
|
||||
entity_src_gen.pdbx_gene_src_scientific_name
|
||||
entity_src_gen.plasmid_name
|
||||
|
||||
entity_src_nat.entity_id
|
||||
entity_src_nat.pdbx_src_id
|
||||
entity_src_nat.pdbx_beg_seq_num
|
||||
entity_src_nat.pdbx_end_seq_num
|
||||
entity_src_nat.pdbx_organism_scientific
|
||||
entity_src_nat.pdbx_plasmid_name
|
||||
|
||||
pdbx_entity_instance_feature.ordinal
|
||||
pdbx_entity_instance_feature.feature_type
|
||||
pdbx_entity_instance_feature.details
|
||||
pdbx_entity_instance_feature.asym_id
|
||||
pdbx_entity_instance_feature.comp_id
|
||||
pdbx_entity_instance_feature.seq_num
|
||||
pdbx_entity_instance_feature.auth_asym_id
|
||||
pdbx_entity_instance_feature.auth_comp_id
|
||||
pdbx_entity_instance_feature.auth_seq_num
|
||||
|
||||
pdbx_entity_src_syn.entity_id
|
||||
pdbx_entity_src_syn.pdbx_src_id
|
||||
pdbx_entity_src_syn.pdbx_beg_seq_num
|
||||
pdbx_entity_src_syn.pdbx_end_seq_num
|
||||
pdbx_entity_src_syn.organism_scientific
|
||||
|
||||
pdbx_entity_branch.entity_id
|
||||
pdbx_entity_branch.type
|
||||
|
||||
pdbx_entity_branch_list.entity_id
|
||||
pdbx_entity_branch_list.comp_id
|
||||
pdbx_entity_branch_list.num
|
||||
pdbx_entity_branch_list.hetero
|
||||
|
||||
pdbx_entity_branch_link.link_id
|
||||
pdbx_entity_branch_link.entity_id
|
||||
pdbx_entity_branch_link.entity_branch_list_num_1
|
||||
pdbx_entity_branch_link.comp_id_1
|
||||
pdbx_entity_branch_link.atom_id_1
|
||||
pdbx_entity_branch_link.leaving_atom_id_1
|
||||
pdbx_entity_branch_link.atom_stereo_config_1
|
||||
pdbx_entity_branch_link.entity_branch_list_num_2
|
||||
pdbx_entity_branch_link.comp_id_2
|
||||
pdbx_entity_branch_link.atom_id_2
|
||||
pdbx_entity_branch_link.leaving_atom_id_2
|
||||
pdbx_entity_branch_link.atom_stereo_config_2
|
||||
pdbx_entity_branch_link.value_order
|
||||
pdbx_entity_branch_link.details
|
||||
|
||||
pdbx_branch_scheme.asym_id
|
||||
pdbx_branch_scheme.entity_id
|
||||
pdbx_branch_scheme.mon_id
|
||||
pdbx_branch_scheme.num
|
||||
pdbx_branch_scheme.auth_asym_id
|
||||
pdbx_branch_scheme.auth_mon_id
|
||||
pdbx_branch_scheme.auth_seq_num
|
||||
pdbx_branch_scheme.hetero
|
||||
pdbx_branch_scheme.pdb_mon_id
|
||||
pdbx_branch_scheme.pdb_asym_id
|
||||
pdbx_branch_scheme.pdb_seq_num
|
||||
|
||||
pdbx_entity_branch_descriptor.ordinal
|
||||
pdbx_entity_branch_descriptor.entity_id
|
||||
pdbx_entity_branch_descriptor.descriptor
|
||||
pdbx_entity_branch_descriptor.type
|
||||
pdbx_entity_branch_descriptor.program
|
||||
pdbx_entity_branch_descriptor.program_version
|
||||
|
||||
pdbx_entity_nonpoly.entity_id
|
||||
pdbx_entity_nonpoly.name
|
||||
pdbx_entity_nonpoly.comp_id
|
||||
|
||||
pdbx_nonpoly_scheme.asym_id
|
||||
pdbx_nonpoly_scheme.entity_id
|
||||
pdbx_nonpoly_scheme.mon_id
|
||||
pdbx_nonpoly_scheme.ndb_seq_num
|
||||
pdbx_nonpoly_scheme.pdb_seq_num
|
||||
pdbx_nonpoly_scheme.auth_seq_num
|
||||
pdbx_nonpoly_scheme.pdb_mon_id
|
||||
pdbx_nonpoly_scheme.auth_mon_id
|
||||
pdbx_nonpoly_scheme.pdb_strand_id
|
||||
pdbx_nonpoly_scheme.pdb_ins_code
|
||||
|
||||
entry.id
|
||||
|
||||
audit_conform.dict_name
|
||||
audit_conform.dict_version
|
||||
audit_conform.dict_location
|
||||
|
||||
database_2.database_id
|
||||
database_2.database_code
|
||||
|
||||
audit_author.name
|
||||
audit_author.pdbx_ordinal
|
||||
audit_author.identifier_ORCID
|
||||
|
||||
citation.id
|
||||
citation.title
|
||||
citation.journal_abbrev
|
||||
citation.journal_volume
|
||||
citation.page_first
|
||||
citation.page_last
|
||||
citation.year
|
||||
citation.journal_id_ASTM
|
||||
citation.country
|
||||
citation.journal_id_ISSN
|
||||
citation.journal_id_CSD
|
||||
citation.book_publisher
|
||||
citation.pdbx_database_id_PubMed
|
||||
citation.pdbx_database_id_DOI
|
||||
|
||||
citation_author.citation_id
|
||||
citation_author.name
|
||||
citation_author.ordinal
|
||||
|
||||
exptl.entry_id
|
||||
exptl.method
|
||||
|
||||
struct.entry_id
|
||||
struct.title
|
||||
struct.pdbx_descriptor
|
||||
|
||||
struct_asym.id
|
||||
struct_asym.pdbx_blank_PDB_chainid_flag
|
||||
struct_asym.pdbx_modified
|
||||
struct_asym.entity_id
|
||||
struct_asym.details
|
||||
|
||||
struct_conf.conf_type_id
|
||||
struct_conf.id
|
||||
struct_conf.pdbx_PDB_helix_id
|
||||
struct_conf.beg_label_comp_id
|
||||
struct_conf.beg_label_asym_id
|
||||
struct_conf.beg_label_seq_id
|
||||
struct_conf.pdbx_beg_PDB_ins_code
|
||||
struct_conf.end_label_comp_id
|
||||
struct_conf.end_label_asym_id
|
||||
struct_conf.end_label_seq_id
|
||||
struct_conf.pdbx_end_PDB_ins_code
|
||||
struct_conf.beg_auth_comp_id
|
||||
struct_conf.beg_auth_asym_id
|
||||
struct_conf.beg_auth_seq_id
|
||||
struct_conf.end_auth_comp_id
|
||||
struct_conf.end_auth_asym_id
|
||||
struct_conf.end_auth_seq_id
|
||||
struct_conf.pdbx_PDB_helix_class
|
||||
struct_conf.details
|
||||
struct_conf.pdbx_PDB_helix_length
|
||||
|
||||
struct_conn.id
|
||||
struct_conn.conn_type_id
|
||||
struct_conn.pdbx_PDB_id
|
||||
struct_conn.ptnr1_label_asym_id
|
||||
struct_conn.ptnr1_label_comp_id
|
||||
struct_conn.ptnr1_label_seq_id
|
||||
struct_conn.ptnr1_label_atom_id
|
||||
struct_conn.pdbx_ptnr1_label_alt_id
|
||||
struct_conn.pdbx_ptnr1_PDB_ins_code
|
||||
struct_conn.pdbx_ptnr1_standard_comp_id
|
||||
struct_conn.ptnr1_symmetry
|
||||
struct_conn.ptnr2_label_asym_id
|
||||
struct_conn.ptnr2_label_comp_id
|
||||
struct_conn.ptnr2_label_seq_id
|
||||
struct_conn.ptnr2_label_atom_id
|
||||
struct_conn.pdbx_ptnr2_label_alt_id
|
||||
struct_conn.pdbx_ptnr2_PDB_ins_code
|
||||
struct_conn.ptnr1_auth_asym_id
|
||||
struct_conn.ptnr1_auth_comp_id
|
||||
struct_conn.ptnr1_auth_seq_id
|
||||
struct_conn.ptnr2_auth_asym_id
|
||||
struct_conn.ptnr2_auth_comp_id
|
||||
struct_conn.ptnr2_auth_seq_id
|
||||
struct_conn.ptnr2_symmetry
|
||||
struct_conn.pdbx_ptnr3_label_atom_id
|
||||
struct_conn.pdbx_ptnr3_label_seq_id
|
||||
struct_conn.pdbx_ptnr3_label_comp_id
|
||||
struct_conn.pdbx_ptnr3_label_asym_id
|
||||
struct_conn.pdbx_ptnr3_label_alt_id
|
||||
struct_conn.pdbx_ptnr3_PDB_ins_code
|
||||
struct_conn.details
|
||||
struct_conn.pdbx_dist_value
|
||||
struct_conn.pdbx_value_order
|
||||
|
||||
struct_conn_type.id
|
||||
struct_conn_type.criteria
|
||||
struct_conn_type.reference
|
||||
|
||||
struct_keywords.entry_id
|
||||
struct_keywords.pdbx_keywords
|
||||
struct_keywords.text
|
||||
|
||||
struct_ncs_oper.id
|
||||
struct_ncs_oper.code
|
||||
struct_ncs_oper.matrix
|
||||
struct_ncs_oper.vector
|
||||
struct_ncs_oper.details
|
||||
|
||||
struct_sheet_range.sheet_id
|
||||
struct_sheet_range.id
|
||||
struct_sheet_range.beg_label_comp_id
|
||||
struct_sheet_range.beg_label_asym_id
|
||||
struct_sheet_range.beg_label_seq_id
|
||||
struct_sheet_range.pdbx_beg_PDB_ins_code
|
||||
struct_sheet_range.end_label_comp_id
|
||||
struct_sheet_range.end_label_asym_id
|
||||
struct_sheet_range.end_label_seq_id
|
||||
struct_sheet_range.pdbx_end_PDB_ins_code
|
||||
struct_sheet_range.beg_auth_comp_id
|
||||
struct_sheet_range.beg_auth_asym_id
|
||||
struct_sheet_range.beg_auth_seq_id
|
||||
struct_sheet_range.end_auth_comp_id
|
||||
struct_sheet_range.end_auth_asym_id
|
||||
struct_sheet_range.end_auth_seq_id
|
||||
|
||||
struct_site.id
|
||||
struct_site.pdbx_evidence_code
|
||||
struct_site.pdbx_auth_asym_id
|
||||
struct_site.pdbx_auth_comp_id
|
||||
struct_site.pdbx_auth_seq_id
|
||||
struct_site.pdbx_auth_ins_code
|
||||
struct_site.pdbx_num_residues
|
||||
struct_site.details
|
||||
|
||||
struct_site_gen.id
|
||||
struct_site_gen.site_id
|
||||
struct_site_gen.pdbx_num_res
|
||||
struct_site_gen.label_comp_id
|
||||
struct_site_gen.label_asym_id
|
||||
struct_site_gen.label_seq_id
|
||||
struct_site_gen.pdbx_auth_ins_code
|
||||
struct_site_gen.auth_comp_id
|
||||
struct_site_gen.auth_asym_id
|
||||
struct_site_gen.auth_seq_id
|
||||
struct_site_gen.label_atom_id
|
||||
struct_site_gen.label_alt_id
|
||||
struct_site_gen.symmetry
|
||||
struct_site_gen.details
|
||||
|
||||
symmetry.entry_id
|
||||
symmetry.cell_setting
|
||||
symmetry.Int_Tables_number
|
||||
symmetry.space_group_name_Hall
|
||||
symmetry.space_group_name_H-M
|
||||
|
||||
pdbx_molecule.instance_id
|
||||
pdbx_molecule.prd_id
|
||||
pdbx_molecule.asym_id
|
||||
|
||||
pdbx_molecule_features.prd_id
|
||||
pdbx_molecule_features.name
|
||||
pdbx_molecule_features.type
|
||||
pdbx_molecule_features.class
|
||||
pdbx_molecule_features.details
|
||||
|
||||
pdbx_reference_entity_link.prd_id
|
||||
pdbx_reference_entity_link.link_id
|
||||
pdbx_reference_entity_link.link_class
|
||||
pdbx_reference_entity_link.ref_entity_id_1
|
||||
pdbx_reference_entity_link.entity_seq_num_1
|
||||
pdbx_reference_entity_link.comp_id_1
|
||||
pdbx_reference_entity_link.atom_id_1
|
||||
pdbx_reference_entity_link.ref_entity_id_2
|
||||
pdbx_reference_entity_link.entity_seq_num_2
|
||||
pdbx_reference_entity_link.comp_id_2
|
||||
pdbx_reference_entity_link.atom_id_2
|
||||
pdbx_reference_entity_link.value_order
|
||||
pdbx_reference_entity_link.component_1
|
||||
pdbx_reference_entity_link.component_2
|
||||
pdbx_reference_entity_link.details
|
||||
|
||||
pdbx_reference_entity_list.prd_id
|
||||
pdbx_reference_entity_list.ref_entity_id
|
||||
pdbx_reference_entity_list.component_id
|
||||
pdbx_reference_entity_list.type
|
||||
pdbx_reference_entity_list.details
|
||||
|
||||
pdbx_reference_entity_poly_link.prd_id
|
||||
pdbx_reference_entity_poly_link.ref_entity_id
|
||||
pdbx_reference_entity_poly_link.link_id
|
||||
pdbx_reference_entity_poly_link.atom_id_1
|
||||
pdbx_reference_entity_poly_link.comp_id_1
|
||||
pdbx_reference_entity_poly_link.entity_seq_num_1
|
||||
pdbx_reference_entity_poly_link.atom_id_2
|
||||
pdbx_reference_entity_poly_link.comp_id_2
|
||||
pdbx_reference_entity_poly_link.entity_seq_num_2
|
||||
pdbx_reference_entity_poly_link.value_order
|
||||
pdbx_reference_entity_poly_link.component_id
|
||||
|
||||
pdbx_struct_assembly.id
|
||||
pdbx_struct_assembly.details
|
||||
pdbx_struct_assembly.method_details
|
||||
pdbx_struct_assembly.oligomeric_details
|
||||
pdbx_struct_assembly.oligomeric_count
|
||||
|
||||
pdbx_struct_assembly_gen.assembly_id
|
||||
pdbx_struct_assembly_gen.oper_expression
|
||||
pdbx_struct_assembly_gen.asym_id_list
|
||||
|
||||
pdbx_struct_oper_list.id
|
||||
pdbx_struct_oper_list.type
|
||||
pdbx_struct_oper_list.name
|
||||
pdbx_struct_oper_list.symmetry_operation
|
||||
pdbx_struct_oper_list.matrix
|
||||
pdbx_struct_oper_list.vector
|
||||
|
||||
pdbx_struct_mod_residue.id
|
||||
pdbx_struct_mod_residue.label_asym_id
|
||||
pdbx_struct_mod_residue.label_seq_id
|
||||
pdbx_struct_mod_residue.label_comp_id
|
||||
pdbx_struct_mod_residue.auth_asym_id
|
||||
pdbx_struct_mod_residue.auth_seq_id
|
||||
pdbx_struct_mod_residue.auth_comp_id
|
||||
pdbx_struct_mod_residue.PDB_ins_code
|
||||
pdbx_struct_mod_residue.parent_comp_id
|
||||
pdbx_struct_mod_residue.details
|
||||
|
||||
pdbx_unobs_or_zero_occ_residues.id
|
||||
pdbx_unobs_or_zero_occ_residues.PDB_model_num
|
||||
pdbx_unobs_or_zero_occ_residues.polymer_flag
|
||||
pdbx_unobs_or_zero_occ_residues.occupancy_flag
|
||||
pdbx_unobs_or_zero_occ_residues.auth_asym_id
|
||||
pdbx_unobs_or_zero_occ_residues.auth_comp_id
|
||||
pdbx_unobs_or_zero_occ_residues.auth_seq_id
|
||||
pdbx_unobs_or_zero_occ_residues.PDB_ins_code
|
||||
pdbx_unobs_or_zero_occ_residues.label_asym_id
|
||||
pdbx_unobs_or_zero_occ_residues.label_comp_id
|
||||
pdbx_unobs_or_zero_occ_residues.label_seq_id
|
||||
|
||||
ihm_struct_assembly.id
|
||||
ihm_struct_assembly.name
|
||||
ihm_struct_assembly.description
|
||||
|
||||
ihm_struct_assembly_details.id
|
||||
ihm_struct_assembly_details.assembly_id
|
||||
ihm_struct_assembly_details.parent_assembly_id
|
||||
ihm_struct_assembly_details.entity_description
|
||||
ihm_struct_assembly_details.entity_id
|
||||
ihm_struct_assembly_details.asym_id
|
||||
ihm_struct_assembly_details.entity_poly_segment_id
|
||||
|
||||
ihm_model_representation.id
|
||||
ihm_model_representation.name
|
||||
ihm_model_representation.details
|
||||
|
||||
ihm_model_representation_details.id
|
||||
ihm_model_representation_details.representation_id
|
||||
ihm_model_representation_details.entity_id
|
||||
ihm_model_representation_details.entity_description
|
||||
ihm_model_representation_details.entity_asym_id
|
||||
ihm_model_representation_details.entity_poly_segment_id
|
||||
ihm_model_representation_details.model_object_primitive
|
||||
ihm_model_representation_details.starting_model_id
|
||||
ihm_model_representation_details.model_mode
|
||||
ihm_model_representation_details.model_granularity
|
||||
ihm_model_representation_details.model_object_count
|
||||
|
||||
ihm_external_reference_info.reference_id
|
||||
ihm_external_reference_info.reference_provider
|
||||
ihm_external_reference_info.reference_type
|
||||
ihm_external_reference_info.reference
|
||||
ihm_external_reference_info.refers_to
|
||||
ihm_external_reference_info.associated_url
|
||||
|
||||
ihm_external_files.id
|
||||
ihm_external_files.reference_id
|
||||
ihm_external_files.file_path
|
||||
ihm_external_files.content_type
|
||||
ihm_external_files.file_size_bytes
|
||||
ihm_external_files.details
|
||||
|
||||
ihm_dataset_list.id
|
||||
ihm_dataset_list.data_type
|
||||
ihm_dataset_list.database_hosted
|
||||
|
||||
ihm_dataset_group.id
|
||||
ihm_dataset_group.name
|
||||
ihm_dataset_group.application
|
||||
ihm_dataset_group.details
|
||||
|
||||
ihm_dataset_group_link.group_id
|
||||
ihm_dataset_group_link.dataset_list_id
|
||||
|
||||
ihm_dataset_external_reference.id
|
||||
ihm_dataset_external_reference.dataset_list_id
|
||||
ihm_dataset_external_reference.file_id
|
||||
|
||||
ihm_dataset_related_db_reference.id
|
||||
ihm_dataset_related_db_reference.dataset_list_id
|
||||
ihm_dataset_related_db_reference.db_name
|
||||
ihm_dataset_related_db_reference.accession_code
|
||||
ihm_dataset_related_db_reference.version
|
||||
ihm_dataset_related_db_reference.details
|
||||
|
||||
ihm_related_datasets.dataset_list_id_derived
|
||||
ihm_related_datasets.dataset_list_id_primary
|
||||
|
||||
ihm_poly_residue_feature.ordinal_id
|
||||
ihm_poly_residue_feature.feature_id
|
||||
ihm_poly_residue_feature.entity_id
|
||||
ihm_poly_residue_feature.asym_id
|
||||
ihm_poly_residue_feature.seq_id_begin
|
||||
ihm_poly_residue_feature.comp_id_begin
|
||||
ihm_poly_residue_feature.seq_id_end
|
||||
ihm_poly_residue_feature.comp_id_end
|
||||
|
||||
ihm_feature_list.feature_id
|
||||
ihm_feature_list.feature_type
|
||||
ihm_feature_list.entity_type
|
||||
|
||||
ihm_cross_link_list.id
|
||||
ihm_cross_link_list.group_id
|
||||
ihm_cross_link_list.entity_description_1
|
||||
ihm_cross_link_list.entity_id_1
|
||||
ihm_cross_link_list.seq_id_1
|
||||
ihm_cross_link_list.comp_id_1
|
||||
ihm_cross_link_list.entity_description_2
|
||||
ihm_cross_link_list.entity_id_2
|
||||
ihm_cross_link_list.seq_id_2
|
||||
ihm_cross_link_list.comp_id_2
|
||||
ihm_cross_link_list.linker_type
|
||||
ihm_cross_link_list.dataset_list_id
|
||||
|
||||
ihm_cross_link_restraint.id
|
||||
ihm_cross_link_restraint.group_id
|
||||
ihm_cross_link_restraint.entity_id_1
|
||||
ihm_cross_link_restraint.asym_id_1
|
||||
ihm_cross_link_restraint.seq_id_1
|
||||
ihm_cross_link_restraint.atom_id_1
|
||||
ihm_cross_link_restraint.comp_id_1
|
||||
ihm_cross_link_restraint.entity_id_2
|
||||
ihm_cross_link_restraint.asym_id_2
|
||||
ihm_cross_link_restraint.seq_id_2
|
||||
ihm_cross_link_restraint.atom_id_2
|
||||
ihm_cross_link_restraint.comp_id_2
|
||||
ihm_cross_link_restraint.restraint_type
|
||||
ihm_cross_link_restraint.conditional_crosslink_flag
|
||||
ihm_cross_link_restraint.model_granularity
|
||||
ihm_cross_link_restraint.distance_threshold
|
||||
ihm_cross_link_restraint.psi
|
||||
ihm_cross_link_restraint.sigma_1
|
||||
ihm_cross_link_restraint.sigma_2
|
||||
|
||||
ihm_cross_link_result_parameters.id
|
||||
ihm_cross_link_result_parameters.restraint_id
|
||||
ihm_cross_link_result_parameters.model_id
|
||||
ihm_cross_link_result_parameters.psi
|
||||
ihm_cross_link_result_parameters.sigma_1
|
||||
ihm_cross_link_result_parameters.sigma_2
|
||||
|
||||
ihm_sas_restraint.id
|
||||
ihm_sas_restraint.dataset_list_id
|
||||
ihm_sas_restraint.model_id
|
||||
ihm_sas_restraint.struct_assembly_id
|
||||
ihm_sas_restraint.profile_segment_flag
|
||||
ihm_sas_restraint.fitting_atom_type
|
||||
ihm_sas_restraint.fitting_method
|
||||
ihm_sas_restraint.fitting_state
|
||||
ihm_sas_restraint.radius_of_gyration
|
||||
ihm_sas_restraint.chi_value
|
||||
ihm_sas_restraint.details
|
||||
|
||||
ihm_derived_distance_restraint.id
|
||||
ihm_derived_distance_restraint.group_id
|
||||
ihm_derived_distance_restraint.feature_id_1
|
||||
ihm_derived_distance_restraint.feature_id_2
|
||||
ihm_derived_distance_restraint.group_conditionality
|
||||
ihm_derived_distance_restraint.restraint_type
|
||||
ihm_derived_distance_restraint.distance_upper_limit
|
||||
ihm_derived_distance_restraint.random_exclusion_fraction
|
||||
ihm_derived_distance_restraint.dataset_list_id
|
||||
|
||||
ihm_2dem_class_average_restraint.id
|
||||
ihm_2dem_class_average_restraint.dataset_list_id
|
||||
ihm_2dem_class_average_restraint.number_raw_micrographs
|
||||
ihm_2dem_class_average_restraint.pixel_size_width
|
||||
ihm_2dem_class_average_restraint.pixel_size_height
|
||||
ihm_2dem_class_average_restraint.image_resolution
|
||||
ihm_2dem_class_average_restraint.image_segment_flag
|
||||
ihm_2dem_class_average_restraint.number_of_projections
|
||||
ihm_2dem_class_average_restraint.struct_assembly_id
|
||||
ihm_2dem_class_average_restraint.details
|
||||
|
||||
ihm_2dem_class_average_fitting.id
|
||||
ihm_2dem_class_average_fitting.restraint_id
|
||||
ihm_2dem_class_average_fitting.model_id
|
||||
ihm_2dem_class_average_fitting.cross_correlation_coefficient
|
||||
ihm_2dem_class_average_fitting.rot_matrix
|
||||
ihm_2dem_class_average_fitting.tr_vector
|
||||
|
||||
ihm_3dem_restraint.id
|
||||
ihm_3dem_restraint.dataset_list_id
|
||||
ihm_3dem_restraint.fitting_method
|
||||
ihm_3dem_restraint.struct_assembly_id
|
||||
ihm_3dem_restraint.number_of_gaussians
|
||||
ihm_3dem_restraint.model_id
|
||||
ihm_3dem_restraint.cross_correlation_coefficient
|
||||
|
||||
ihm_predicted_contact_restraint.id
|
||||
ihm_predicted_contact_restraint.group_id
|
||||
ihm_predicted_contact_restraint.entity_id_1
|
||||
ihm_predicted_contact_restraint.asym_id_1
|
||||
ihm_predicted_contact_restraint.seq_id_1
|
||||
ihm_predicted_contact_restraint.comp_id_1
|
||||
ihm_predicted_contact_restraint.rep_atom_1
|
||||
ihm_predicted_contact_restraint.entity_id_2
|
||||
ihm_predicted_contact_restraint.asym_id_2
|
||||
ihm_predicted_contact_restraint.seq_id_2
|
||||
ihm_predicted_contact_restraint.comp_id_2
|
||||
ihm_predicted_contact_restraint.rep_atom_2
|
||||
ihm_predicted_contact_restraint.restraint_type
|
||||
ihm_predicted_contact_restraint.distance_lower_limit
|
||||
ihm_predicted_contact_restraint.distance_upper_limit
|
||||
ihm_predicted_contact_restraint.probability
|
||||
ihm_predicted_contact_restraint.model_granularity
|
||||
ihm_predicted_contact_restraint.dataset_list_id
|
||||
ihm_predicted_contact_restraint.software_id
|
||||
|
||||
ihm_starting_model_details.starting_model_id
|
||||
ihm_starting_model_details.entity_id
|
||||
ihm_starting_model_details.entity_description
|
||||
ihm_starting_model_details.asym_id
|
||||
ihm_starting_model_details.entity_poly_segment_id
|
||||
ihm_starting_model_details.starting_model_source
|
||||
ihm_starting_model_details.starting_model_auth_asym_id
|
||||
ihm_starting_model_details.starting_model_sequence_offset
|
||||
ihm_starting_model_details.dataset_list_id
|
||||
|
||||
ihm_starting_comparative_models.id
|
||||
ihm_starting_comparative_models.starting_model_id
|
||||
ihm_starting_comparative_models.starting_model_auth_asym_id
|
||||
ihm_starting_comparative_models.starting_model_seq_id_begin
|
||||
ihm_starting_comparative_models.starting_model_seq_id_end
|
||||
ihm_starting_comparative_models.template_auth_asym_id
|
||||
ihm_starting_comparative_models.template_seq_id_begin
|
||||
ihm_starting_comparative_models.template_seq_id_end
|
||||
ihm_starting_comparative_models.template_sequence_identity
|
||||
ihm_starting_comparative_models.template_sequence_identity_denominator
|
||||
ihm_starting_comparative_models.template_dataset_list_id
|
||||
ihm_starting_comparative_models.alignment_file_id
|
||||
|
||||
ihm_starting_model_coord.starting_model_id
|
||||
ihm_starting_model_coord.group_PDB
|
||||
ihm_starting_model_coord.id
|
||||
ihm_starting_model_coord.type_symbol
|
||||
ihm_starting_model_coord.atom_id
|
||||
ihm_starting_model_coord.comp_id
|
||||
ihm_starting_model_coord.entity_id
|
||||
ihm_starting_model_coord.asym_id
|
||||
ihm_starting_model_coord.seq_id
|
||||
ihm_starting_model_coord.Cartn_x
|
||||
ihm_starting_model_coord.Cartn_y
|
||||
ihm_starting_model_coord.Cartn_z
|
||||
ihm_starting_model_coord.B_iso_or_equiv
|
||||
ihm_starting_model_coord.ordinal_id
|
||||
|
||||
ihm_starting_model_seq_dif.id
|
||||
ihm_starting_model_seq_dif.entity_id
|
||||
ihm_starting_model_seq_dif.asym_id
|
||||
ihm_starting_model_seq_dif.seq_id
|
||||
ihm_starting_model_seq_dif.comp_id
|
||||
ihm_starting_model_seq_dif.starting_model_id
|
||||
ihm_starting_model_seq_dif.db_asym_id
|
||||
ihm_starting_model_seq_dif.db_seq_id
|
||||
ihm_starting_model_seq_dif.db_comp_id
|
||||
ihm_starting_model_seq_dif.details
|
||||
|
||||
ihm_modeling_protocol.id
|
||||
ihm_modeling_protocol.protocol_name
|
||||
ihm_modeling_protocol.num_steps
|
||||
|
||||
ihm_modeling_protocol_details.id
|
||||
ihm_modeling_protocol_details.protocol_id
|
||||
ihm_modeling_protocol_details.step_id
|
||||
ihm_modeling_protocol_details.struct_assembly_id
|
||||
ihm_modeling_protocol_details.dataset_group_id
|
||||
ihm_modeling_protocol_details.struct_assembly_description
|
||||
ihm_modeling_protocol_details.step_name
|
||||
ihm_modeling_protocol_details.step_method
|
||||
ihm_modeling_protocol_details.num_models_begin
|
||||
ihm_modeling_protocol_details.num_models_end
|
||||
ihm_modeling_protocol_details.multi_scale_flag
|
||||
ihm_modeling_protocol_details.multi_state_flag
|
||||
ihm_modeling_protocol_details.ordered_flag
|
||||
ihm_modeling_protocol_details.software_id
|
||||
ihm_modeling_protocol_details.script_file_id
|
||||
|
||||
ihm_modeling_post_process.id
|
||||
ihm_modeling_post_process.protocol_id
|
||||
ihm_modeling_post_process.analysis_id
|
||||
ihm_modeling_post_process.step_id
|
||||
ihm_modeling_post_process.type
|
||||
ihm_modeling_post_process.feature
|
||||
ihm_modeling_post_process.num_models_begin
|
||||
ihm_modeling_post_process.num_models_end
|
||||
|
||||
ihm_ensemble_info.ensemble_id
|
||||
ihm_ensemble_info.ensemble_name
|
||||
ihm_ensemble_info.post_process_id
|
||||
ihm_ensemble_info.model_group_id
|
||||
ihm_ensemble_info.ensemble_clustering_method
|
||||
ihm_ensemble_info.ensemble_clustering_feature
|
||||
ihm_ensemble_info.num_ensemble_models
|
||||
ihm_ensemble_info.num_ensemble_models_deposited
|
||||
ihm_ensemble_info.ensemble_precision_value
|
||||
ihm_ensemble_info.ensemble_file_id
|
||||
|
||||
ihm_localization_density_files.id
|
||||
ihm_localization_density_files.file_id
|
||||
ihm_localization_density_files.ensemble_id
|
||||
ihm_localization_density_files.entity_id
|
||||
ihm_localization_density_files.asym_id
|
||||
ihm_localization_density_files.entity_poly_segment_id
|
||||
|
||||
ihm_model_list.model_id
|
||||
ihm_model_list.model_name
|
||||
ihm_model_list.assembly_id
|
||||
ihm_model_list.protocol_id
|
||||
ihm_model_list.representation_id
|
||||
|
||||
ihm_model_group.id
|
||||
ihm_model_group.name
|
||||
ihm_model_group.details
|
||||
|
||||
ihm_model_group_link.group_id
|
||||
ihm_model_group_link.model_id
|
||||
|
||||
ihm_model_representative.id
|
||||
ihm_model_representative.model_group_id
|
||||
ihm_model_representative.model_id
|
||||
ihm_model_representative.selection_criteria
|
||||
|
||||
ihm_sphere_obj_site.id
|
||||
ihm_sphere_obj_site.entity_id
|
||||
ihm_sphere_obj_site.seq_id_begin
|
||||
ihm_sphere_obj_site.seq_id_end
|
||||
ihm_sphere_obj_site.asym_id
|
||||
ihm_sphere_obj_site.Cartn_x
|
||||
ihm_sphere_obj_site.Cartn_y
|
||||
ihm_sphere_obj_site.Cartn_z
|
||||
ihm_sphere_obj_site.object_radius
|
||||
ihm_sphere_obj_site.rmsf
|
||||
ihm_sphere_obj_site.model_id
|
||||
|
||||
ihm_gaussian_obj_site.id
|
||||
ihm_gaussian_obj_site.entity_id
|
||||
ihm_gaussian_obj_site.seq_id_begin
|
||||
ihm_gaussian_obj_site.seq_id_end
|
||||
ihm_gaussian_obj_site.asym_id
|
||||
ihm_gaussian_obj_site.mean_Cartn_x
|
||||
ihm_gaussian_obj_site.mean_Cartn_y
|
||||
ihm_gaussian_obj_site.mean_Cartn_z
|
||||
ihm_gaussian_obj_site.weight
|
||||
ihm_gaussian_obj_site.covariance_matrix
|
||||
ihm_gaussian_obj_site.model_id
|
||||
|
||||
ihm_gaussian_obj_ensemble.id
|
||||
ihm_gaussian_obj_ensemble.entity_id
|
||||
ihm_gaussian_obj_ensemble.seq_id_begin
|
||||
ihm_gaussian_obj_ensemble.seq_id_end
|
||||
ihm_gaussian_obj_ensemble.asym_id
|
||||
ihm_gaussian_obj_ensemble.mean_Cartn_x
|
||||
ihm_gaussian_obj_ensemble.mean_Cartn_y
|
||||
ihm_gaussian_obj_ensemble.mean_Cartn_z
|
||||
ihm_gaussian_obj_ensemble.weight
|
||||
ihm_gaussian_obj_ensemble.covariance_matrix
|
||||
ihm_gaussian_obj_ensemble.ensemble_id
|
||||
|
||||
ihm_multi_state_modeling.state_id
|
||||
ihm_multi_state_modeling.state_group_id
|
||||
ihm_multi_state_modeling.population_fraction
|
||||
ihm_multi_state_modeling.population_fraction_sd
|
||||
ihm_multi_state_modeling.state_type
|
||||
ihm_multi_state_modeling.state_name
|
||||
ihm_multi_state_modeling.experiment_type
|
||||
ihm_multi_state_modeling.details
|
||||
|
76
data/cif-field-names/mmtf-filter.csv
Normal file
76
data/cif-field-names/mmtf-filter.csv
Normal file
@@ -0,0 +1,76 @@
|
||||
cell.length_a
|
||||
cell.length_b
|
||||
cell.length_c
|
||||
cell.angle_alpha
|
||||
cell.angle_beta
|
||||
cell.angle_gamma
|
||||
|
||||
symmetry.space_group_name_H-M
|
||||
|
||||
entry.id
|
||||
|
||||
struct.title
|
||||
|
||||
pdbx_database_status.recvd_initial_deposition_date
|
||||
|
||||
pdbx_audit_revision_history.revision_date
|
||||
|
||||
struct_ncs_oper
|
||||
|
||||
pdbx_struct_assembly_gen
|
||||
|
||||
pdbx_struct_oper_list
|
||||
|
||||
entity.id
|
||||
entity.type
|
||||
entity.pdbx_description
|
||||
|
||||
entity_poly.entity_id
|
||||
entity_poly.pdbx_seq_one_letter_code
|
||||
entity_poly.pdbx_strand_id
|
||||
|
||||
exptl.method
|
||||
|
||||
refine.ls_d_res_low
|
||||
refine.ls_R_factor_R_free
|
||||
refine.ls_R_factor_R_work
|
||||
|
||||
atom_site.pdbx_formal_charge
|
||||
atom_site.label_atom_id
|
||||
atom_site.type_symbol
|
||||
|
||||
chem_comp.id
|
||||
chem_comp.type
|
||||
chem_comp.name
|
||||
|
||||
chem_comp_bond
|
||||
|
||||
atom_site.Cartn_x
|
||||
atom_site.Cartn_y
|
||||
atom_site.Cartn_z
|
||||
atom_site.B_iso_or_equiv
|
||||
atom_site.id
|
||||
atom_site.label_alt_id
|
||||
atom_site.occupancy
|
||||
atom_site.label_seq_id
|
||||
atom_site.label_comp_id
|
||||
|
||||
struct_sheet_range.id
|
||||
struct_sheet_range.beg_label_asym_id
|
||||
struct_sheet_range.beg_label_seq_id
|
||||
struct_sheet_range.pdbx_beg_PDB_ins_code
|
||||
struct_sheet_range.end_label_asym_id
|
||||
struct_sheet_range.end_label_seq_id
|
||||
struct_sheet_range.pdbx_end_PDB_ins_code
|
||||
struct_conf.conf_type_id
|
||||
struct_conf.id
|
||||
struct_conf.beg_label_asym_id
|
||||
struct_conf.beg_label_seq_id
|
||||
struct_conf.pdbx_beg_PDB_ins_code
|
||||
struct_conf.end_label_asym_id
|
||||
struct_conf.end_label_seq_id
|
||||
struct_conf.pdbx_end_PDB_ins_code
|
||||
|
||||
atom_site.pdbx_PDB_ins_code
|
||||
atom_site.label_asym_id
|
||||
atom_site.auth_asym_id
|
||||
|
@@ -1,22 +0,0 @@
|
||||
const { generate } = require('graphql-code-generator')
|
||||
const path = require('path')
|
||||
|
||||
const basePath = path.join(__dirname, '..', '..', 'src', 'mol-model-props', 'rcsb', 'graphql')
|
||||
|
||||
generate({
|
||||
schema: 'http://rest-dev.rcsb.org/graphql',
|
||||
documents: {
|
||||
[path.join(basePath, 'symmetry.gql.ts')]: {
|
||||
loader: path.join(__dirname, 'loader.js')
|
||||
},
|
||||
},
|
||||
generates: {
|
||||
[path.join(basePath, 'types.ts')]: {
|
||||
plugins: ['time', 'typescript-common', 'typescript-client']
|
||||
}
|
||||
},
|
||||
overwrite: true,
|
||||
config: path.join(__dirname, 'codegen.json')
|
||||
}, true).then(
|
||||
() => console.log('done')
|
||||
).catch(e => console.error(e))
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"flattenTypes": true,
|
||||
"generatorConfig": {
|
||||
"immutableTypes": true
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
const { parse } = require('graphql');
|
||||
const { readFileSync } = require('fs');
|
||||
|
||||
module.exports = function(docString, config) {
|
||||
const str = readFileSync(docString, { encoding: 'utf-8' }).trim()
|
||||
.replace(/^export default `/, '')
|
||||
.replace(/`$/, '')
|
||||
return [
|
||||
{
|
||||
filePath: docString,
|
||||
content: parse(str)
|
||||
}
|
||||
];
|
||||
};
|
||||
35
docs/interesting-pdb-entries.md
Normal file
35
docs/interesting-pdb-entries.md
Normal file
@@ -0,0 +1,35 @@
|
||||
* Cyclic polymers (1sfi, 6dny, 1HVZ)
|
||||
* B-DNA (1bna)
|
||||
* Missing carbonyl oxygen (1gfl)
|
||||
* Mono-saccharides with alt locs (1B5F)
|
||||
* Microheterogeneity
|
||||
* Protein (1EJG, 3NIR)
|
||||
* DNA (3VOK)
|
||||
* PNA: peptide nucleic acid (5eme, 1xj9)
|
||||
* Peptide derived residues
|
||||
* GFP chromophores (5Z6Y)
|
||||
* Nucleotides that don’t have a parent base set, i.e. detect purine/pyrimidine from geometry (THX in 1AUL, OMC in e.g. 5D3G)
|
||||
* Bases with modified ring atoms
|
||||
* DZ has C1 instead of N1 (e.g. 6I4N)
|
||||
* DP has N5 instead of C5 and C7 instead of N7 (e.g. 6I4N)
|
||||
* Beta & Gamma peptides (e.g. 1GAC, 6PQF)
|
||||
* Mixed (heterogeneous) all-atom/trace-only RNA model (1JGQ)
|
||||
* Polymers with residues with missing trace atoms (e.g. 2QFJ)
|
||||
* Modified RNA bases (1y26, 5L4O)
|
||||
* Discontinuous chains, i.e. gaps in the sequence (3sn6)
|
||||
* Lots of sheets (1cbs)
|
||||
* DNA (2np2, 1d66)
|
||||
* C-alpha only (2rcj)
|
||||
* Not cyclic, but termini are backbone-only and within distance but seqIds are not compatible (6SW3)
|
||||
* Close backbone atoms but not linked (e.g. 4HIV)
|
||||
* Non-standard residues
|
||||
* Protein (1BRR, 5Z6Y)
|
||||
* DNA (5D3G)
|
||||
* Multiple models with different sets of ligands or missing ligands (1J6T, 1VRC, 2ICY, 1O2F)
|
||||
* Long linear sugar chain (4HG6)
|
||||
* Anisotropic B-factors/Ellipsoids (1EJG)
|
||||
* NOS bridges (LYS-CSO in 7B0L, 6ZWJ, 6ZWH)
|
||||
|
||||
Assembly symmetries
|
||||
* 5M30 (Assembly 1, C3 local and pseudo)
|
||||
* 1RB8 (Assembly 1, I global)
|
||||
@@ -6,133 +6,64 @@ Model Server is a tool for preprocessing and querying macromolecular structure d
|
||||
Installing and Running
|
||||
=====================
|
||||
|
||||
Getting the code (use node 8+):
|
||||
Requires nodejs 8+.
|
||||
|
||||
## From GitHub
|
||||
|
||||
```
|
||||
git clone https://github.com/molstar/molstar
|
||||
npm install
|
||||
```
|
||||
|
||||
Customize configuration at ``src/server/model/config.ts`` to point to your data and which custom properties to include (see the [Custom Properties](#custom-properties) section). Alternatively, the config can be edited in the compiled version in ``build/node_modules/servers/model/config.js``.
|
||||
|
||||
Afterwards, build the project:
|
||||
Afterwards, build the project source:
|
||||
|
||||
```
|
||||
npm run build
|
||||
npm run build-tsc
|
||||
```
|
||||
|
||||
(or run watch mode for automatic rebuilds: ``npm run watch``)
|
||||
and run the server by
|
||||
|
||||
Running the server locally for testing:
|
||||
```
|
||||
npm run model-server
|
||||
```
|
||||
or
|
||||
```
|
||||
node build/node_modules/servers/model/server
|
||||
node lib/commonjs/servers/model/server/server
|
||||
```
|
||||
|
||||
In production it is a good idea to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
|
||||
## From NPM
|
||||
|
||||
```
|
||||
npm install --production molstar
|
||||
./model-server
|
||||
```
|
||||
|
||||
(or ``node node_modules\.bin\model-server`` in Windows).
|
||||
|
||||
The NPM package contains all the tools mentioned here as "binaries":
|
||||
|
||||
- ``model-server``
|
||||
- ``model-server-query``
|
||||
- ``model-server-preprocess``
|
||||
|
||||
|
||||
## Memory issues
|
||||
### Production use
|
||||
|
||||
In production it is required to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
|
||||
|
||||
|
||||
### Memory issues
|
||||
|
||||
Sometimes nodejs might run into problems with memory. This is usually resolved by adding the ``--max-old-space-size=8192`` parameter.
|
||||
|
||||
Preprocessor
|
||||
============
|
||||
## Preprocessor
|
||||
|
||||
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. See the [Custom Properties](#custom-properties) section for providing custom properties.
|
||||
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. ``node lib/commonjs/servers/model/preprocess`` or ``model-server-preprocess`` binary from the NPM package.
|
||||
|
||||
## Usage
|
||||
|
||||
The app works in two modes: single files and folders.
|
||||
## Local Mode
|
||||
|
||||
Single files:
|
||||
|
||||
```
|
||||
node build\node_modules\servers\model\preprocess -i input.cif [-oc output.cif] [-ob output.bcif] [--cfg config.json]
|
||||
```
|
||||
|
||||
Folder:
|
||||
```
|
||||
node build\node_modules\servers\model\preprocess -fin input_folder [-foc output_cif_folder] [-fob output_bcif_folder] [--cfg config.json]
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
The config speficies the maximum number of processes to use (in case of folder processing) and defines sources and parameters for custom properties.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"numProcesses": 4,
|
||||
"customProperties": {
|
||||
"sources": [
|
||||
"./properties/pdbe"
|
||||
],
|
||||
"params": {
|
||||
"PDBe": {
|
||||
"UseFileSource": false,
|
||||
"API": {
|
||||
"residuewise_outlier_summary": "https://www.ebi.ac.uk/pdbe/api/validation/residuewise_outlier_summary/entry",
|
||||
"preferred_assembly": "https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary",
|
||||
"struct_ref_domain": "https://www.ebi.ac.uk/pdbe/api/mappings/sequence_domains"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
The server can be run in local/file based mode using ``node lib/commonjs/servers/model/query`` (``model-server-query`` binary from the NPM package).
|
||||
|
||||
Custom Properties
|
||||
=================
|
||||
|
||||
It is possible to provide property descriptors that transform data to internal representation and define how it should be exported into one or mode CIF categories. Examples of this are located in the ``mol-model-props`` module and are linked to the server in the config and ``servers/model/properties``.
|
||||
This feature is still in development.
|
||||
|
||||
Local Mode
|
||||
==========
|
||||
|
||||
The server can be run in local/file based mode:
|
||||
|
||||
```
|
||||
node build/node_modules/servers/model/server jobs.json
|
||||
```
|
||||
|
||||
where ``jobs.json`` is an array of
|
||||
|
||||
```ts
|
||||
type LocalInput = {
|
||||
input: string,
|
||||
output: string,
|
||||
query: QueryName,
|
||||
modelNums?: number[],
|
||||
params?: any,
|
||||
binary?: boolean
|
||||
}[]
|
||||
```
|
||||
|
||||
For example
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"input": "c:/test/quick/1tqn.cif",
|
||||
"output": "c:/test/quick/localapi/1tqn_full.cif",
|
||||
"query": "full"
|
||||
},
|
||||
{
|
||||
"input": "c:/test/quick/1tqn.cif",
|
||||
"output": "c:/test/quick/localapi/1tqn_full.bcif",
|
||||
"query": "full",
|
||||
"params": {}
|
||||
},
|
||||
{
|
||||
"input": "c:/test/quick/1cbs_updated.cif",
|
||||
"output": "c:/test/quick/localapi/1cbs_ligint.cif",
|
||||
"query": "residueInteraction",
|
||||
"params": {
|
||||
"atom_site": { "label_comp_id": "REA" }
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
It is possible to provide property descriptors that transform data to internal representation and define how it should be exported into one or mode CIF categories. Examples of this are located in the ``mol-model-props`` module and are linked to the server in the config and ``servers/model/properties``.
|
||||
@@ -7,107 +7,64 @@ It uses the text based CIF and BinaryCIF formats to deliver the data to the clie
|
||||
|
||||
For quick info about the benefits of using the server, check out the [examples](examples.md).
|
||||
|
||||
Installing the Server
|
||||
Installing and Running
|
||||
=====================
|
||||
|
||||
- Install [Node.js](https://nodejs.org/en/) (tested on Node 6.* and 7.*; x64 version is strongly preferred).
|
||||
- Get the code.
|
||||
- Prepare the data.
|
||||
- Run the server.
|
||||
Requires nodejs 8+.
|
||||
|
||||
Preparing the Data
|
||||
------------------
|
||||
## From GitHub
|
||||
|
||||
```
|
||||
git clone https://github.com/molstar/molstar
|
||||
npm install
|
||||
```
|
||||
|
||||
Afterwards, build the project source:
|
||||
|
||||
```
|
||||
npm run build-tsc
|
||||
```
|
||||
|
||||
and run the server by
|
||||
|
||||
```
|
||||
node lib/commonjs/servers/volume/server
|
||||
```
|
||||
|
||||
## From NPM
|
||||
|
||||
```
|
||||
npm install --production molstar
|
||||
./volume-server
|
||||
```
|
||||
|
||||
(or ``node node_modules\.bin\volume-server`` in Windows).
|
||||
|
||||
The NPM package contains all the tools mentioned here as "binaries":
|
||||
|
||||
- ``volume-server``
|
||||
- ``volume-server-pack``
|
||||
- ``volume-server-query``
|
||||
|
||||
|
||||
### Production use
|
||||
|
||||
In production it is required to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
|
||||
|
||||
|
||||
### Memory issues
|
||||
|
||||
Sometimes nodejs might run into problems with memory. This is usually resolved by adding the ``--max-old-space-size=8192`` parameter.
|
||||
|
||||
|
||||
## Preparing the Data
|
||||
|
||||
For the server to work, CCP4/MAP (models 0, 1, 2 are supported) input data need to be converted into a custom block format.
|
||||
To achieve this, use the ``pack`` application.
|
||||
To achieve this, use the ``pack`` application (``node lib/commonjs/servers/volume/pack`` or ``volume-server-pack`` binary from the NPM package).
|
||||
|
||||
- To prepare data from x-ray based methods, use:
|
||||
## Local Mode
|
||||
|
||||
```
|
||||
node pack -xray main.ccp4 diff.ccp4 out.mdb
|
||||
```
|
||||
|
||||
- For EM data, use:
|
||||
|
||||
```
|
||||
node pack -em em.map out.mdb
|
||||
```
|
||||
|
||||
Running the Server
|
||||
------------------
|
||||
|
||||
- Install production dependencies:
|
||||
|
||||
```
|
||||
npm install --only=production
|
||||
```
|
||||
|
||||
- Update ``server-config.js`` to link to your data and optionally tweak the other parameters.
|
||||
|
||||
- Run it:
|
||||
|
||||
```
|
||||
node server
|
||||
```
|
||||
|
||||
In production it is a good idea to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
|
||||
|
||||
### Local Mode
|
||||
|
||||
The program ``local`` in the build folder can be used to query the data without running a http server.
|
||||
|
||||
- ``node local`` prints the program usage.
|
||||
- ``node local jobs.json`` takes a list of jobs to execute in JSON format. A job entry is defined by this interface:
|
||||
|
||||
```TypeScript
|
||||
interface JobEntry {
|
||||
source: {
|
||||
filename: string,
|
||||
name: string,
|
||||
id: string
|
||||
},
|
||||
query: {
|
||||
kind: 'box' | 'cell',
|
||||
space?: 'fractional' | 'cartesian',
|
||||
bottomLeft?: number[],
|
||||
topRight?: number[],
|
||||
}
|
||||
params: {
|
||||
/** Determines the detail level as specified in server-config */
|
||||
detail?: number,
|
||||
/**
|
||||
* Determines the sampling level:
|
||||
* 1: Original data
|
||||
* 2: Downsampled by factor 1/2
|
||||
* ...
|
||||
* N: downsampled 1/2^(N-1)
|
||||
*/
|
||||
forcedSamplingLevel?: number,
|
||||
asBinary: boolean,
|
||||
},
|
||||
outputFolder: string
|
||||
}
|
||||
```
|
||||
|
||||
Example ``jobs.json`` file content:
|
||||
|
||||
```TypeScript
|
||||
[{
|
||||
source: {
|
||||
filename: `g:/test/mdb/emd-8116.mdb`,
|
||||
name: 'em',
|
||||
id: '8116',
|
||||
},
|
||||
query: {
|
||||
kind: 'cell'
|
||||
},
|
||||
params: {
|
||||
detail: 4,
|
||||
asBinary: true
|
||||
},
|
||||
outputFolder: 'g:/test/local-test'
|
||||
}]
|
||||
```
|
||||
The program ``lib/commonjs/servers/volume/pack`` (``volume-server-query`` in NPM package) can be used to query the data without running a http server.
|
||||
|
||||
## Navigating the Source Code
|
||||
|
||||
@@ -122,8 +79,8 @@ The source code is split into 2 mains parts: ``pack`` and ``server``:
|
||||
Consuming the Data
|
||||
==================
|
||||
|
||||
The data can be consumed in any (modern) browser using the [CIFTools.js library](https://github.com/dsehnal/CIFTools.js) (or any other piece of code that can read text or binary CIF).
|
||||
The data can be consumed in any (modern) browser using the [ciftools library](https://github.com/molstar/ciftools) (or any other piece of code that can read text or binary CIF).
|
||||
|
||||
The [Data Format](DataFormat.md) document gives a detailed description of the server response format.
|
||||
|
||||
As a reference/example of the server usage, please see the implementation in [LiteMol](https://github.com/dsehnal/LiteMol) ([CIF.ts + Data.ts](https://github.com/dsehnal/LiteMol/tree/master/src/lib/Core/Formats/Density), [UI](https://github.com/dsehnal/LiteMol/tree/master/src/Viewer/Extensions/DensityStreaming)) or in Mol*.
|
||||
As a reference/example of the server usage is available in Mol* ``mol-plugin`` module.
|
||||
884
examples/867861-core.cif
Normal file
884
examples/867861-core.cif
Normal file
@@ -0,0 +1,884 @@
|
||||
#######################################################################
|
||||
#
|
||||
# This file contains crystal structure data downloaded from the
|
||||
# Cambridge Structural Database (CSD) hosted by the Cambridge
|
||||
# Crystallographic Data Centre (CCDC).
|
||||
#
|
||||
# Full information about CCDC data access policies and citation
|
||||
# guidelines are available at http://www.ccdc.cam.ac.uk/access/V1
|
||||
#
|
||||
# Audit and citation data items may have been added by the CCDC.
|
||||
# Please retain this information to preserve the provenance of
|
||||
# this file and to allow appropriate attribution of the data.
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
data_n1379
|
||||
_audit_block_doi 10.5517/ccy42jn
|
||||
_database_code_depnum_ccdc_archive 'CCDC 867861'
|
||||
loop_
|
||||
_citation_id
|
||||
_citation_doi
|
||||
_citation_year
|
||||
1 10.1002/chem.201202070 2012
|
||||
_audit_update_record
|
||||
;
|
||||
2012-02-20 deposited with the CCDC.
|
||||
2016-10-08 downloaded from the CCDC.
|
||||
;
|
||||
|
||||
_audit_creation_method SHELXL-97
|
||||
_chemical_name_systematic
|
||||
;
|
||||
?
|
||||
;
|
||||
_chemical_name_common ?
|
||||
_chemical_melting_point ?
|
||||
_chemical_formula_moiety 'C76 H90 N10 O14 4(C2 F3 O2) 4(C2 H3 N)'
|
||||
_chemical_formula_sum 'C92 H102 F12 N14 O22'
|
||||
_chemical_formula_weight 1983.88
|
||||
|
||||
loop_
|
||||
_atom_type_symbol
|
||||
_atom_type_description
|
||||
_atom_type_scat_dispersion_real
|
||||
_atom_type_scat_dispersion_imag
|
||||
_atom_type_scat_source
|
||||
C C 0.0181 0.0091 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
|
||||
H H 0.0000 0.0000 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
|
||||
N N 0.0311 0.0180 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
|
||||
O O 0.0492 0.0322 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
|
||||
F F 0.0727 0.0534 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
|
||||
|
||||
_symmetry_cell_setting Triclinic
|
||||
_symmetry_space_group_name_H-M P-1
|
||||
|
||||
loop_
|
||||
_symmetry_equiv_pos_as_xyz
|
||||
'x, y, z'
|
||||
'-x, -y, -z'
|
||||
|
||||
_cell_length_a 11.0829(8)
|
||||
_cell_length_b 14.6829(10)
|
||||
_cell_length_c 16.8532(17)
|
||||
_cell_angle_alpha 105.728(6)
|
||||
_cell_angle_beta 100.310(6)
|
||||
_cell_angle_gamma 110.620(4)
|
||||
_cell_volume 2353.3(3)
|
||||
_cell_formula_units_Z 1
|
||||
_cell_measurement_temperature 100(2)
|
||||
_cell_measurement_reflns_used 5934
|
||||
_cell_measurement_theta_min 2.86
|
||||
_cell_measurement_theta_max 64.30
|
||||
|
||||
_exptl_crystal_description plate
|
||||
_exptl_crystal_colour violet
|
||||
_exptl_crystal_size_max 0.57
|
||||
_exptl_crystal_size_mid 0.18
|
||||
_exptl_crystal_size_min 0.05
|
||||
_exptl_crystal_density_meas ?
|
||||
_exptl_crystal_density_diffrn 1.400
|
||||
_exptl_crystal_density_method ?
|
||||
_exptl_crystal_F_000 1036
|
||||
_exptl_absorpt_coefficient_mu 0.995
|
||||
_exptl_absorpt_correction_type integration
|
||||
_exptl_absorpt_correction_T_min 0.6022
|
||||
_exptl_absorpt_correction_T_max 0.9482
|
||||
_exptl_absorpt_process_details 'XPREP, face-indexed'
|
||||
|
||||
_exptl_special_details
|
||||
;
|
||||
?
|
||||
;
|
||||
|
||||
_diffrn_ambient_temperature 100(2)
|
||||
_diffrn_radiation_wavelength 1.54178
|
||||
_diffrn_radiation_type CuK\a
|
||||
_diffrn_radiation_source microsource
|
||||
_diffrn_radiation_monochromator 'Quazar optics'
|
||||
_diffrn_measurement_device_type 'Bruker APEX-II CCD'
|
||||
_diffrn_measurement_method '\f and \w scans'
|
||||
_diffrn_detector_area_resol_mean ?
|
||||
_diffrn_reflns_number 16613
|
||||
_diffrn_reflns_av_R_equivalents 0.1477
|
||||
_diffrn_reflns_av_sigmaI/netI 0.1112
|
||||
_diffrn_reflns_limit_h_min -12
|
||||
_diffrn_reflns_limit_h_max 8
|
||||
_diffrn_reflns_limit_k_min -17
|
||||
_diffrn_reflns_limit_k_max 17
|
||||
_diffrn_reflns_limit_l_min -19
|
||||
_diffrn_reflns_limit_l_max 19
|
||||
_diffrn_reflns_theta_min 2.86
|
||||
_diffrn_reflns_theta_max 64.94
|
||||
_reflns_number_total 7680
|
||||
_reflns_number_gt 5560
|
||||
_reflns_threshold_expression >2sigma(I)
|
||||
|
||||
_computing_data_collection 'Bruker APEX2'
|
||||
_computing_cell_refinement 'Bruker SAINT'
|
||||
_computing_data_reduction 'Bruker SAINT'
|
||||
_computing_structure_solution 'SHELXS-97 (Sheldrick, 2008)'
|
||||
_computing_structure_refinement 'SHELXL-97 (Sheldrick, 2008)'
|
||||
_computing_molecular_graphics 'Bruker SHELXTL'
|
||||
_computing_publication_material 'Bruker SHELXTL'
|
||||
|
||||
_refine_special_details
|
||||
;
|
||||
Refinement of F^2^ against ALL reflections. The weighted R-factor wR and
|
||||
goodness of fit S are based on F^2^, conventional R-factors R are based
|
||||
on F, with F set to zero for negative F^2^. The threshold expression of
|
||||
F^2^ > 2sigma(F^2^) is used only for calculating R-factors(gt) etc. and is
|
||||
not relevant to the choice of reflections for refinement. R-factors based
|
||||
on F^2^ are statistically about twice as large as those based on F, and R-
|
||||
factors based on ALL data will be even larger.
|
||||
Rigid bond restraints (esd 0.002) were imposed on the displacement parameters,
|
||||
as well as restraints on similar amplitudes (esd 0.002) separated by less
|
||||
than 1.7 Ang. on C27, C29, and N102.
|
||||
Distance restraints were refined on the bond between C28 and C29.
|
||||
;
|
||||
|
||||
_refine_ls_structure_factor_coef Fsqd
|
||||
_refine_ls_matrix_type full
|
||||
_refine_ls_weighting_scheme calc
|
||||
_refine_ls_weighting_details
|
||||
'calc w=1/[\s^2^(Fo^2^)+(0.1912P)^2^+4.8134P] where P=(Fo^2^+2Fc^2^)/3'
|
||||
_atom_sites_solution_primary direct
|
||||
_atom_sites_solution_secondary difmap
|
||||
_atom_sites_solution_hydrogens geom
|
||||
_refine_ls_hydrogen_treatment mixed
|
||||
_refine_ls_extinction_method none
|
||||
_refine_ls_extinction_coef ?
|
||||
_refine_ls_number_reflns 7680
|
||||
_refine_ls_number_parameters 633
|
||||
_refine_ls_number_restraints 1
|
||||
_refine_ls_R_factor_all 0.1349
|
||||
_refine_ls_R_factor_gt 0.1101
|
||||
_refine_ls_wR_factor_ref 0.3402
|
||||
_refine_ls_wR_factor_gt 0.3102
|
||||
_refine_ls_goodness_of_fit_ref 1.089
|
||||
_refine_ls_restrained_S_all 1.096
|
||||
_refine_ls_shift/su_max 0.000
|
||||
_refine_ls_shift/su_mean 0.000
|
||||
|
||||
loop_
|
||||
_atom_site_label
|
||||
_atom_site_type_symbol
|
||||
_atom_site_fract_x
|
||||
_atom_site_fract_y
|
||||
_atom_site_fract_z
|
||||
_atom_site_U_iso_or_equiv
|
||||
_atom_site_adp_type
|
||||
_atom_site_occupancy
|
||||
_atom_site_symmetry_multiplicity
|
||||
_atom_site_calc_flag
|
||||
_atom_site_refinement_flags
|
||||
_atom_site_disorder_assembly
|
||||
_atom_site_disorder_group
|
||||
C1 C -0.3373(4) -0.2086(3) -0.2547(3) 0.0229(10) Uani 1 1 d . . .
|
||||
H1 H -0.3820 -0.2827 -0.2795 0.027 Uiso 1 1 calc R . .
|
||||
C2 C -0.1956(4) -0.0511(3) -0.2602(3) 0.0215(10) Uani 1 1 d . . .
|
||||
H2 H -0.1401 -0.0147 -0.2886 0.026 Uiso 1 1 calc R . .
|
||||
C3 C -0.3583(4) -0.1574(3) -0.1814(3) 0.0213(9) Uani 1 1 d . . .
|
||||
H3 H -0.4168 -0.1960 -0.1558 0.026 Uiso 1 1 calc R . .
|
||||
C4 C -0.2146(4) 0.0039(3) -0.1873(3) 0.0180(9) Uani 1 1 d . . .
|
||||
H4 H -0.1736 0.0780 -0.1660 0.022 Uiso 1 1 calc R . .
|
||||
C5 C -0.2943(4) -0.0488(3) -0.1440(3) 0.0163(9) Uani 1 1 d . . .
|
||||
C6 C -0.3053(4) 0.0091(3) -0.0600(3) 0.0170(9) Uani 1 1 d . . .
|
||||
C7 C -0.3538(4) -0.0444(3) -0.0071(3) 0.0193(9) Uani 1 1 d . . .
|
||||
H7 H -0.3850 -0.1181 -0.0264 0.023 Uiso 1 1 calc R . .
|
||||
C8 C -0.2620(4) 0.1168(3) -0.0291(3) 0.0194(9) Uani 1 1 d . . .
|
||||
H8 H -0.2304 0.1553 -0.0640 0.023 Uiso 1 1 calc R . .
|
||||
C9 C -0.3563(4) 0.0094(3) 0.0725(3) 0.0218(10) Uani 1 1 d . . .
|
||||
H9 H -0.3904 -0.0276 0.1077 0.026 Uiso 1 1 calc R . .
|
||||
C10 C -0.2648(4) 0.1679(3) 0.0515(3) 0.0190(9) Uani 1 1 d . . .
|
||||
H10 H -0.2340 0.2416 0.0724 0.023 Uiso 1 1 calc R . .
|
||||
C11 C -0.3024(4) 0.1707(4) 0.1919(3) 0.0227(10) Uani 1 1 d . . .
|
||||
H11A H -0.3772 0.1277 0.2088 0.027 Uiso 1 1 calc R . .
|
||||
H11B H -0.3094 0.2371 0.1964 0.027 Uiso 1 1 calc R . .
|
||||
C12 C -0.1670(4) 0.1920(3) 0.2509(2) 0.0184(9) Uani 1 1 d . . .
|
||||
C13 C -0.1547(5) 0.1179(4) 0.2849(3) 0.0223(10) Uani 1 1 d . . .
|
||||
H13 H -0.2328 0.0589 0.2788 0.027 Uiso 1 1 calc R . .
|
||||
C14 C -0.0541(4) 0.2821(3) 0.2667(2) 0.0204(9) Uani 1 1 d . . .
|
||||
H14 H -0.0631 0.3352 0.2475 0.024 Uiso 1 1 calc R . .
|
||||
C15 C -0.0272(5) 0.1313(4) 0.3277(3) 0.0231(10) Uani 1 1 d . . .
|
||||
H15 H -0.0192 0.0806 0.3506 0.028 Uiso 1 1 calc R . .
|
||||
C16 C 0.0731(4) 0.2946(3) 0.3110(2) 0.0195(9) Uani 1 1 d . . .
|
||||
C17 C 0.0890(4) 0.2163(3) 0.3381(2) 0.0204(10) Uani 1 1 d . . .
|
||||
C18 C 0.2252(5) 0.2149(4) 0.3687(3) 0.0273(11) Uani 1 1 d . . .
|
||||
H18A H 0.2965 0.2872 0.3968 0.033 Uiso 1 1 calc R . .
|
||||
H18B H 0.2237 0.1802 0.4116 0.033 Uiso 1 1 calc R . .
|
||||
C19 C 0.2862(4) 0.4582(4) 0.3974(3) 0.0247(10) Uani 1 1 d . . .
|
||||
H19 H 0.3032 0.4532 0.4530 0.030 Uiso 1 1 calc R . .
|
||||
C20 C 0.3577(5) 0.5371(4) 0.3739(3) 0.0279(11) Uani 1 1 d . . .
|
||||
C21 C 0.4805(5) 0.6358(4) 0.4267(3) 0.0333(12) Uani 1 1 d . . .
|
||||
H21A H 0.4882 0.6869 0.3975 0.040 Uiso 1 1 calc R . .
|
||||
H21B H 0.4699 0.6656 0.4837 0.040 Uiso 1 1 calc R . .
|
||||
C22 C 0.6303(6) 0.5857(4) 0.3599(3) 0.0374(12) Uani 1 1 d . . .
|
||||
H22A H 0.6523 0.6416 0.3355 0.045 Uiso 1 1 calc R . .
|
||||
H22B H 0.5494 0.5242 0.3176 0.045 Uiso 1 1 calc R . .
|
||||
C23 C 0.7460(6) 0.5575(5) 0.3762(4) 0.0413(13) Uani 1 1 d . . .
|
||||
H23A H 0.7730 0.5406 0.3231 0.050 Uiso 1 1 calc R . .
|
||||
H23B H 0.8246 0.6169 0.4226 0.050 Uiso 1 1 calc R . .
|
||||
C24 C 0.7952(6) 0.4206(5) 0.3967(4) 0.0496(16) Uani 1 1 d . . .
|
||||
H24A H 0.8893 0.4743 0.4264 0.060 Uiso 1 1 calc R . .
|
||||
H24B H 0.7870 0.3874 0.3353 0.060 Uiso 1 1 calc R . .
|
||||
C25 C 0.7663(11) 0.3428(7) 0.4361(4) 0.074(3) Uani 1 1 d . . .
|
||||
H25A H 0.8372 0.3165 0.4378 0.089 Uiso 1 1 calc R . .
|
||||
H25B H 0.7691 0.3754 0.4965 0.089 Uiso 1 1 calc R . .
|
||||
C26 C 0.6441(8) 0.1838(7) 0.4342(5) 0.071(2) Uani 1 1 d . . .
|
||||
H26A H 0.7153 0.1600 0.4249 0.085 Uiso 1 1 calc R . .
|
||||
H26B H 0.6577 0.2137 0.4970 0.085 Uiso 1 1 calc R . .
|
||||
C27 C 0.5204(10) 0.1080(8) 0.3921(7) 0.125(5) Uani 1 1 d . . .
|
||||
H27A H 0.5220 0.0408 0.3913 0.150 Uiso 1 1 calc R . .
|
||||
H27B H 0.4964 0.1039 0.3313 0.150 Uiso 1 1 calc R . .
|
||||
C28 C 0.3730(9) 0.0886(7) 0.4988(5) 0.097(4) Uani 1 1 d D . .
|
||||
H28A H 0.4284 0.0506 0.5097 0.116 Uiso 1 1 calc R . .
|
||||
H28B H 0.4078 0.1526 0.5510 0.116 Uiso 1 1 calc R . .
|
||||
C29 C 0.2559(11) 0.033(2) 0.4964(8) 0.281(16) Uani 1 1 d D . .
|
||||
H29A H 0.2452 0.0690 0.5518 0.337 Uiso 1 1 calc R . .
|
||||
H29B H 0.2589 -0.0322 0.5000 0.337 Uiso 1 1 calc R . .
|
||||
C30 C 0.0569(12) -0.1026(9) 0.4169(5) 0.089(3) Uani 1 1 d . . .
|
||||
H30A H 0.0442 -0.1134 0.4708 0.107 Uiso 1 1 calc R . .
|
||||
H30B H 0.1035 -0.1448 0.3928 0.107 Uiso 1 1 calc R . .
|
||||
C31 C -0.0702(10) -0.1360(6) 0.3569(6) 0.083(3) Uani 1 1 d . . .
|
||||
H31A H -0.1307 -0.2064 0.3530 0.100 Uiso 1 1 calc R . .
|
||||
H31B H -0.1113 -0.0878 0.3776 0.100 Uiso 1 1 calc R . .
|
||||
C32 C -0.1964(9) -0.1774(5) 0.2168(5) 0.067(2) Uani 1 1 d . . .
|
||||
H32A H -0.2564 -0.2441 0.2195 0.080 Uiso 1 1 calc R . .
|
||||
H32B H -0.2342 -0.1258 0.2343 0.080 Uiso 1 1 calc R . .
|
||||
C33 C -0.1881(7) -0.1926(5) 0.1297(4) 0.0593(19) Uani 1 1 d . . .
|
||||
H33A H -0.2803 -0.2327 0.0880 0.071 Uiso 1 1 calc R . .
|
||||
H33B H -0.1354 -0.2340 0.1169 0.071 Uiso 1 1 calc R . .
|
||||
C34 C -0.0909(4) -0.0989(4) 0.0440(3) 0.0231(10) Uani 1 1 d . . .
|
||||
C35 C -0.1178(5) -0.1907(4) -0.0206(3) 0.0290(11) Uani 1 1 d . . .
|
||||
H35 H -0.1660 -0.2560 -0.0162 0.035 Uiso 1 1 calc R . .
|
||||
C36 C -0.0214(4) -0.0005(3) 0.0371(3) 0.0182(9) Uani 1 1 d . . .
|
||||
C37 C 0.0055(4) 0.0950(3) 0.1019(3) 0.0212(10) Uani 1 1 d . . .
|
||||
H37 H -0.0240 0.0948 0.1515 0.025 Uiso 1 1 calc R . .
|
||||
C38 C 0.0734(4) 0.1868(4) 0.0931(3) 0.0249(10) Uani 1 1 d . . .
|
||||
H38 H 0.0914 0.2503 0.1372 0.030 Uiso 1 1 calc R . .
|
||||
N1 N -0.2553(3) -0.1567(3) -0.2921(2) 0.0202(8) Uani 1 1 d . . .
|
||||
N2 N -0.3112(3) 0.1137(3) 0.1013(2) 0.0181(8) Uani 1 1 d . . .
|
||||
N3 N 0.1854(4) 0.3880(3) 0.3242(2) 0.0221(8) Uani 1 1 d . . .
|
||||
N4 N 0.1947(4) 0.4236(3) 0.2574(2) 0.0281(9) Uani 1 1 d . . .
|
||||
N5 N 0.2991(4) 0.5136(3) 0.2881(3) 0.0315(10) Uani 1 1 d . . .
|
||||
O1 O 0.6028(3) 0.6210(3) 0.4395(2) 0.0301(8) Uani 1 1 d . . .
|
||||
O2 O 0.7045(4) 0.4689(3) 0.4018(2) 0.0429(10) Uani 1 1 d . . .
|
||||
O3 O 0.6381(7) 0.2580(4) 0.3907(4) 0.0743(17) Uani 1 1 d . . .
|
||||
O4 O 0.4041(4) 0.1218(3) 0.4321(2) 0.0412(10) Uani 1 1 d . . .
|
||||
O5 O 0.1363(5) 0.0023(6) 0.4355(3) 0.0786(19) Uani 1 1 d . . .
|
||||
O6 O -0.0597(6) -0.1394(4) 0.2749(3) 0.0757(17) Uani 1 1 d . . .
|
||||
O7 O -0.1244(3) -0.0939(3) 0.1185(2) 0.0320(8) Uani 1 1 d . . .
|
||||
C101 C 0.6294(5) 0.3676(4) 0.1211(3) 0.0286(11) Uani 1 1 d . . .
|
||||
C102 C 0.5798(8) 0.4458(5) 0.1022(5) 0.066(2) Uani 1 1 d . . .
|
||||
C103 C 0.5077(5) 0.8961(4) 0.2466(3) 0.0342(12) Uani 1 1 d . . .
|
||||
C104 C 0.3819(8) 0.8078(6) 0.2433(5) 0.077(3) Uani 1 1 d . . .
|
||||
C105 C 0.0707(7) 0.4215(5) 0.0313(4) 0.0516(16) Uani 1 1 d . . .
|
||||
C106 C 0.2104(7) 0.4969(6) 0.0645(5) 0.066(2) Uani 1 1 d . . .
|
||||
H10A H 0.2627 0.4718 0.0303 0.099 Uiso 1 1 calc R . .
|
||||
H10B H 0.2471 0.5066 0.1251 0.099 Uiso 1 1 calc R . .
|
||||
H10C H 0.2161 0.5637 0.0606 0.099 Uiso 1 1 calc R . .
|
||||
C107 C 0.0569(7) 0.6249(7) 0.2999(5) 0.071(2) Uani 1 1 d . . .
|
||||
C108 C 0.0316(8) 0.5978(7) 0.2128(5) 0.077(2) Uani 1 1 d . . .
|
||||
H10D H 0.0994 0.5753 0.1954 0.115 Uiso 1 1 calc R . .
|
||||
H10E H 0.0360 0.6581 0.1969 0.115 Uiso 1 1 calc R . .
|
||||
H10F H -0.0588 0.5404 0.1833 0.115 Uiso 1 1 calc R . .
|
||||
O101 O 0.5421(4) 0.2774(3) 0.0882(3) 0.0463(10) Uani 1 1 d . . .
|
||||
O102 O 0.7472(4) 0.4014(3) 0.1666(3) 0.0485(11) Uani 1 1 d . . .
|
||||
O103 O 0.4882(4) 0.9389(3) 0.1955(2) 0.0356(9) Uani 1 1 d . . .
|
||||
O104 O 0.6107(4) 0.9176(3) 0.3029(3) 0.0517(11) Uani 1 1 d . . .
|
||||
F101 F 0.4877(8) 0.4530(7) 0.1408(4) 0.148(3) Uani 1 1 d . . .
|
||||
F102 F 0.5188(6) 0.4177(4) 0.0191(3) 0.105(2) Uani 1 1 d . . .
|
||||
F103 F 0.6733(8) 0.5407(3) 0.1298(5) 0.160(4) Uani 1 1 d . . .
|
||||
F104 F 0.2811(5) 0.7655(4) 0.1734(3) 0.098(2) Uani 1 1 d . . .
|
||||
F105 F 0.3328(8) 0.8406(9) 0.3070(4) 0.233(7) Uani 1 1 d . . .
|
||||
F106 F 0.4002(9) 0.7351(6) 0.2617(7) 0.224(6) Uani 1 1 d . . .
|
||||
N101 N -0.0392(7) 0.3613(5) 0.0045(4) 0.0715(19) Uani 1 1 d . . .
|
||||
N102 N 0.0774(10) 0.6479(13) 0.3716(6) 0.185(7) Uani 1 1 d . . .
|
||||
|
||||
loop_
|
||||
_atom_site_aniso_label
|
||||
_atom_site_aniso_U_11
|
||||
_atom_site_aniso_U_22
|
||||
_atom_site_aniso_U_33
|
||||
_atom_site_aniso_U_23
|
||||
_atom_site_aniso_U_13
|
||||
_atom_site_aniso_U_12
|
||||
C1 0.015(2) 0.023(2) 0.022(2) -0.0003(18) -0.0032(18) 0.0097(17)
|
||||
C2 0.021(2) 0.032(2) 0.012(2) 0.0047(17) -0.0022(17) 0.0168(19)
|
||||
C3 0.0099(19) 0.030(2) 0.021(2) 0.0059(18) -0.0007(17) 0.0104(17)
|
||||
C4 0.017(2) 0.027(2) 0.0111(19) 0.0045(16) -0.0012(16) 0.0157(18)
|
||||
C5 0.0087(18) 0.025(2) 0.0134(19) 0.0028(16) -0.0032(15) 0.0121(16)
|
||||
C6 0.0075(18) 0.031(2) 0.014(2) 0.0067(17) -0.0017(15) 0.0130(17)
|
||||
C7 0.0074(18) 0.029(2) 0.019(2) 0.0047(17) 0.0003(16) 0.0093(17)
|
||||
C8 0.0135(19) 0.028(2) 0.013(2) 0.0039(17) -0.0035(16) 0.0120(17)
|
||||
C9 0.013(2) 0.031(2) 0.020(2) 0.0072(18) 0.0012(17) 0.0105(18)
|
||||
C10 0.0112(19) 0.029(2) 0.018(2) 0.0066(17) 0.0025(16) 0.0122(17)
|
||||
C11 0.019(2) 0.038(2) 0.014(2) 0.0056(18) 0.0059(17) 0.0178(19)
|
||||
C12 0.019(2) 0.029(2) 0.0068(18) -0.0007(16) 0.0013(16) 0.0169(18)
|
||||
C13 0.024(2) 0.030(2) 0.013(2) 0.0023(17) 0.0047(18) 0.0159(19)
|
||||
C14 0.027(2) 0.027(2) 0.0079(19) -0.0015(16) 0.0012(17) 0.0200(19)
|
||||
C15 0.030(2) 0.034(2) 0.012(2) 0.0056(17) 0.0059(18) 0.023(2)
|
||||
C16 0.023(2) 0.028(2) 0.0057(18) -0.0018(16) 0.0027(16) 0.0154(19)
|
||||
C17 0.024(2) 0.032(2) 0.0063(18) -0.0012(16) 0.0008(16) 0.0209(19)
|
||||
C18 0.028(2) 0.040(3) 0.010(2) -0.0024(18) -0.0038(18) 0.025(2)
|
||||
C19 0.023(2) 0.034(2) 0.012(2) -0.0015(18) -0.0024(17) 0.017(2)
|
||||
C20 0.024(2) 0.031(2) 0.019(2) 0.0008(19) -0.0030(19) 0.011(2)
|
||||
C21 0.027(3) 0.034(3) 0.028(3) -0.001(2) 0.001(2) 0.014(2)
|
||||
C22 0.038(3) 0.046(3) 0.027(3) 0.011(2) 0.010(2) 0.018(2)
|
||||
C23 0.039(3) 0.054(3) 0.033(3) 0.012(3) 0.015(2) 0.022(3)
|
||||
C24 0.051(3) 0.061(4) 0.034(3) -0.002(3) 0.006(3) 0.038(3)
|
||||
C25 0.145(8) 0.082(5) 0.039(4) 0.023(4) 0.042(5) 0.090(6)
|
||||
C26 0.068(5) 0.096(6) 0.055(4) 0.020(4) 0.007(4) 0.053(5)
|
||||
C27 0.105(7) 0.115(7) 0.120(8) -0.033(6) -0.051(6) 0.106(7)
|
||||
C28 0.082(6) 0.105(6) 0.049(4) 0.052(4) -0.036(4) -0.012(5)
|
||||
C29 0.074(7) 0.62(4) 0.114(10) 0.252(18) 0.001(7) 0.029(14)
|
||||
C30 0.149(9) 0.141(9) 0.054(5) 0.065(5) 0.057(6) 0.113(8)
|
||||
C31 0.110(7) 0.062(5) 0.082(6) 0.050(4) 0.030(5) 0.021(5)
|
||||
C32 0.094(6) 0.046(4) 0.061(4) 0.021(3) 0.040(4) 0.021(4)
|
||||
C33 0.056(4) 0.048(4) 0.046(4) 0.013(3) 0.018(3) -0.007(3)
|
||||
C34 0.014(2) 0.035(2) 0.014(2) 0.0059(18) -0.0019(17) 0.0096(18)
|
||||
C35 0.025(2) 0.032(2) 0.021(2) 0.0050(19) -0.0033(19) 0.010(2)
|
||||
C36 0.0082(18) 0.030(2) 0.0130(19) 0.0013(17) -0.0030(15) 0.0125(17)
|
||||
C37 0.017(2) 0.032(2) 0.013(2) -0.0004(17) -0.0039(16) 0.0181(19)
|
||||
C38 0.024(2) 0.029(2) 0.016(2) -0.0031(18) -0.0035(18) 0.017(2)
|
||||
N1 0.0187(18) 0.032(2) 0.0087(16) -0.0003(14) -0.0050(14) 0.0193(16)
|
||||
N2 0.0109(16) 0.033(2) 0.0095(16) 0.0031(14) -0.0003(13) 0.0141(15)
|
||||
N3 0.0216(18) 0.030(2) 0.0120(17) -0.0001(15) -0.0016(14) 0.0163(16)
|
||||
N4 0.029(2) 0.029(2) 0.0150(18) 0.0034(16) -0.0032(16) 0.0089(17)
|
||||
N5 0.033(2) 0.032(2) 0.021(2) 0.0036(17) -0.0041(17) 0.0140(18)
|
||||
O1 0.0235(17) 0.0363(18) 0.0205(16) 0.0026(14) 0.0003(13) 0.0105(14)
|
||||
O2 0.054(2) 0.060(2) 0.031(2) 0.0152(18) 0.0199(18) 0.040(2)
|
||||
O3 0.137(5) 0.064(3) 0.083(4) 0.044(3) 0.084(4) 0.073(4)
|
||||
O4 0.0309(19) 0.049(2) 0.043(2) 0.0191(18) -0.0025(16) 0.0215(17)
|
||||
O5 0.045(3) 0.155(6) 0.048(3) 0.062(3) 0.024(2) 0.031(3)
|
||||
O6 0.093(4) 0.048(3) 0.058(3) 0.026(2) -0.016(3) 0.012(3)
|
||||
O7 0.0255(17) 0.045(2) 0.0179(16) 0.0091(14) 0.0051(14) 0.0090(15)
|
||||
C101 0.033(3) 0.030(3) 0.021(2) 0.0047(19) 0.011(2) 0.014(2)
|
||||
C102 0.082(5) 0.053(4) 0.047(4) 0.000(3) -0.010(4) 0.039(4)
|
||||
C103 0.041(3) 0.035(3) 0.021(2) 0.008(2) -0.002(2) 0.017(2)
|
||||
C104 0.073(5) 0.069(5) 0.048(4) 0.042(4) -0.023(4) -0.012(4)
|
||||
C105 0.055(4) 0.045(3) 0.055(4) 0.018(3) 0.001(3) 0.028(3)
|
||||
C106 0.057(4) 0.060(4) 0.070(5) 0.018(4) 0.001(4) 0.026(4)
|
||||
C107 0.041(4) 0.113(7) 0.059(5) 0.035(4) 0.016(3) 0.028(4)
|
||||
C108 0.057(4) 0.081(5) 0.061(5) 0.019(4) 0.011(4) 0.003(4)
|
||||
O101 0.033(2) 0.038(2) 0.060(3) 0.0192(19) 0.0048(19) 0.0098(17)
|
||||
O102 0.041(2) 0.038(2) 0.053(2) 0.0099(18) -0.0001(19) 0.0125(18)
|
||||
O103 0.038(2) 0.043(2) 0.0269(18) 0.0176(16) 0.0086(15) 0.0154(17)
|
||||
O104 0.043(2) 0.055(2) 0.045(2) 0.023(2) -0.0085(19) 0.0130(19)
|
||||
F101 0.159(6) 0.220(8) 0.099(4) 0.007(5) 0.016(4) 0.166(7)
|
||||
F102 0.148(5) 0.067(3) 0.074(3) 0.030(2) -0.031(3) 0.045(3)
|
||||
F103 0.177(7) 0.030(2) 0.180(6) 0.007(3) -0.087(5) 0.030(3)
|
||||
F104 0.073(3) 0.084(3) 0.072(3) 0.054(2) -0.037(2) -0.028(2)
|
||||
F105 0.132(6) 0.291(12) 0.076(4) 0.035(6) 0.034(4) -0.108(8)
|
||||
F106 0.161(7) 0.104(5) 0.286(11) 0.146(7) -0.127(7) -0.041(5)
|
||||
N101 0.063(4) 0.050(3) 0.082(4) 0.025(3) -0.013(3) 0.018(3)
|
||||
N102 0.077(6) 0.35(2) 0.072(6) 0.079(9) 0.015(5) 0.027(9)
|
||||
|
||||
_geom_special_details
|
||||
;
|
||||
All esds (except the esd in the dihedral angle between two l.s. planes)
|
||||
are estimated using the full covariance matrix. The cell esds are taken
|
||||
into account individually in the estimation of esds in distances, angles
|
||||
and torsion angles; correlations between esds in cell parameters are only
|
||||
used when they are defined by crystal symmetry. An approximate (isotropic)
|
||||
treatment of cell esds is used for estimating esds involving l.s. planes.
|
||||
;
|
||||
|
||||
loop_
|
||||
_geom_bond_atom_site_label_1
|
||||
_geom_bond_atom_site_label_2
|
||||
_geom_bond_distance
|
||||
_geom_bond_site_symmetry_2
|
||||
_geom_bond_publ_flag
|
||||
C1 N1 1.334(6) . ?
|
||||
C1 C3 1.367(6) . ?
|
||||
C1 H1 0.9500 . ?
|
||||
C2 N1 1.353(6) . ?
|
||||
C2 C4 1.371(6) . ?
|
||||
C2 H2 0.9500 . ?
|
||||
C3 C5 1.394(6) . ?
|
||||
C3 H3 0.9500 . ?
|
||||
C4 C5 1.403(6) . ?
|
||||
C4 H4 0.9500 . ?
|
||||
C5 C6 1.490(6) . ?
|
||||
C6 C8 1.390(6) . ?
|
||||
C6 C7 1.397(6) . ?
|
||||
C7 C9 1.371(6) . ?
|
||||
C7 H7 0.9500 . ?
|
||||
C8 C10 1.375(6) . ?
|
||||
C8 H8 0.9500 . ?
|
||||
C9 N2 1.342(6) . ?
|
||||
C9 H9 0.9500 . ?
|
||||
C10 N2 1.352(6) . ?
|
||||
C10 H10 0.9500 . ?
|
||||
C11 N2 1.497(5) . ?
|
||||
C11 C12 1.517(6) . ?
|
||||
C11 H11A 0.9900 . ?
|
||||
C11 H11B 0.9900 . ?
|
||||
C12 C14 1.382(6) . ?
|
||||
C12 C13 1.396(6) . ?
|
||||
C13 C15 1.384(6) . ?
|
||||
C13 H13 0.9500 . ?
|
||||
C14 C16 1.395(6) . ?
|
||||
C14 H14 0.9500 . ?
|
||||
C15 C17 1.383(7) . ?
|
||||
C15 H15 0.9500 . ?
|
||||
C16 C17 1.400(6) . ?
|
||||
C16 N3 1.418(6) . ?
|
||||
C17 C18 1.515(6) . ?
|
||||
C18 N1 1.505(5) 2 ?
|
||||
C18 H18A 0.9900 . ?
|
||||
C18 H18B 0.9900 . ?
|
||||
C19 N3 1.356(5) . ?
|
||||
C19 C20 1.357(7) . ?
|
||||
C19 H19 0.9500 . ?
|
||||
C20 N5 1.366(6) . ?
|
||||
C20 C21 1.491(6) . ?
|
||||
C21 O1 1.435(6) . ?
|
||||
C21 H21A 0.9900 . ?
|
||||
C21 H21B 0.9900 . ?
|
||||
C22 O1 1.429(6) . ?
|
||||
C22 C23 1.484(8) . ?
|
||||
C22 H22A 0.9900 . ?
|
||||
C22 H22B 0.9900 . ?
|
||||
C23 O2 1.431(7) . ?
|
||||
C23 H23A 0.9900 . ?
|
||||
C23 H23B 0.9900 . ?
|
||||
C24 O2 1.420(7) . ?
|
||||
C24 C25 1.442(11) . ?
|
||||
C24 H24A 0.9900 . ?
|
||||
C24 H24B 0.9900 . ?
|
||||
C25 O3 1.416(11) . ?
|
||||
C25 H25A 0.9900 . ?
|
||||
C25 H25B 0.9900 . ?
|
||||
C26 C27 1.331(12) . ?
|
||||
C26 O3 1.481(9) . ?
|
||||
C26 H26A 0.9900 . ?
|
||||
C26 H26B 0.9900 . ?
|
||||
C27 O4 1.605(11) . ?
|
||||
C27 H27A 0.9900 . ?
|
||||
C27 H27B 0.9900 . ?
|
||||
C28 C29 1.252(12) . ?
|
||||
C28 O4 1.391(8) . ?
|
||||
C28 H28A 0.9900 . ?
|
||||
C28 H28B 0.9900 . ?
|
||||
C29 O5 1.361(11) . ?
|
||||
C29 H29A 0.9900 . ?
|
||||
C29 H29B 0.9900 . ?
|
||||
C30 O5 1.388(12) . ?
|
||||
C30 C31 1.407(13) . ?
|
||||
C30 H30A 0.9900 . ?
|
||||
C30 H30B 0.9900 . ?
|
||||
C31 O6 1.396(10) . ?
|
||||
C31 H31A 0.9900 . ?
|
||||
C31 H31B 0.9900 . ?
|
||||
C32 C33 1.449(9) . ?
|
||||
C32 O6 1.464(10) . ?
|
||||
C32 H32A 0.9900 . ?
|
||||
C32 H32B 0.9900 . ?
|
||||
C33 O7 1.453(7) . ?
|
||||
C33 H33A 0.9900 . ?
|
||||
C33 H33B 0.9900 . ?
|
||||
C34 O7 1.362(5) . ?
|
||||
C34 C35 1.377(7) . ?
|
||||
C34 C36 1.425(7) . ?
|
||||
C35 C38 1.404(7) 2 ?
|
||||
C35 H35 0.9500 . ?
|
||||
C36 C36 1.417(9) 2 ?
|
||||
C36 C37 1.417(6) . ?
|
||||
C37 C38 1.356(7) . ?
|
||||
C37 H37 0.9500 . ?
|
||||
C38 C35 1.404(7) 2 ?
|
||||
C38 H38 0.9500 . ?
|
||||
N1 C18 1.505(5) 2 ?
|
||||
N3 N4 1.370(5) . ?
|
||||
N4 N5 1.300(6) . ?
|
||||
C101 O101 1.227(6) . ?
|
||||
C101 O102 1.232(6) . ?
|
||||
C101 C102 1.518(9) . ?
|
||||
C102 F103 1.301(9) . ?
|
||||
C102 F102 1.318(8) . ?
|
||||
C102 F101 1.324(11) . ?
|
||||
C103 O104 1.224(6) . ?
|
||||
C103 O103 1.227(6) . ?
|
||||
C103 C104 1.512(9) . ?
|
||||
C104 F106 1.260(10) . ?
|
||||
C104 F104 1.290(7) . ?
|
||||
C104 F105 1.341(14) . ?
|
||||
C105 N101 1.139(9) . ?
|
||||
C105 C106 1.443(10) . ?
|
||||
C106 H10A 0.9800 . ?
|
||||
C106 H10B 0.9800 . ?
|
||||
C106 H10C 0.9800 . ?
|
||||
C107 N102 1.118(11) . ?
|
||||
C107 C108 1.360(11) . ?
|
||||
C108 H10D 0.9800 . ?
|
||||
C108 H10E 0.9800 . ?
|
||||
C108 H10F 0.9800 . ?
|
||||
|
||||
loop_
|
||||
_geom_angle_atom_site_label_1
|
||||
_geom_angle_atom_site_label_2
|
||||
_geom_angle_atom_site_label_3
|
||||
_geom_angle
|
||||
_geom_angle_site_symmetry_1
|
||||
_geom_angle_site_symmetry_3
|
||||
_geom_angle_publ_flag
|
||||
N1 C1 C3 121.3(4) . . ?
|
||||
N1 C1 H1 119.3 . . ?
|
||||
C3 C1 H1 119.3 . . ?
|
||||
N1 C2 C4 120.4(4) . . ?
|
||||
N1 C2 H2 119.8 . . ?
|
||||
C4 C2 H2 119.8 . . ?
|
||||
C1 C3 C5 120.4(4) . . ?
|
||||
C1 C3 H3 119.8 . . ?
|
||||
C5 C3 H3 119.8 . . ?
|
||||
C2 C4 C5 120.4(4) . . ?
|
||||
C2 C4 H4 119.8 . . ?
|
||||
C5 C4 H4 119.8 . . ?
|
||||
C3 C5 C4 116.9(4) . . ?
|
||||
C3 C5 C6 121.8(4) . . ?
|
||||
C4 C5 C6 121.2(4) . . ?
|
||||
C8 C6 C7 117.6(4) . . ?
|
||||
C8 C6 C5 122.4(4) . . ?
|
||||
C7 C6 C5 119.9(4) . . ?
|
||||
C9 C7 C6 120.1(4) . . ?
|
||||
C9 C7 H7 120.0 . . ?
|
||||
C6 C7 H7 120.0 . . ?
|
||||
C10 C8 C6 120.4(4) . . ?
|
||||
C10 C8 H8 119.8 . . ?
|
||||
C6 C8 H8 119.8 . . ?
|
||||
N2 C9 C7 120.9(4) . . ?
|
||||
N2 C9 H9 119.5 . . ?
|
||||
C7 C9 H9 119.5 . . ?
|
||||
N2 C10 C8 120.3(4) . . ?
|
||||
N2 C10 H10 119.8 . . ?
|
||||
C8 C10 H10 119.8 . . ?
|
||||
N2 C11 C12 107.7(3) . . ?
|
||||
N2 C11 H11A 110.2 . . ?
|
||||
C12 C11 H11A 110.2 . . ?
|
||||
N2 C11 H11B 110.2 . . ?
|
||||
C12 C11 H11B 110.2 . . ?
|
||||
H11A C11 H11B 108.5 . . ?
|
||||
C14 C12 C13 119.9(4) . . ?
|
||||
C14 C12 C11 120.0(4) . . ?
|
||||
C13 C12 C11 120.0(4) . . ?
|
||||
C15 C13 C12 119.2(4) . . ?
|
||||
C15 C13 H13 120.4 . . ?
|
||||
C12 C13 H13 120.4 . . ?
|
||||
C12 C14 C16 119.7(4) . . ?
|
||||
C12 C14 H14 120.2 . . ?
|
||||
C16 C14 H14 120.2 . . ?
|
||||
C17 C15 C13 122.1(4) . . ?
|
||||
C17 C15 H15 118.9 . . ?
|
||||
C13 C15 H15 118.9 . . ?
|
||||
C14 C16 C17 121.1(4) . . ?
|
||||
C14 C16 N3 117.0(4) . . ?
|
||||
C17 C16 N3 121.8(4) . . ?
|
||||
C15 C17 C16 117.5(4) . . ?
|
||||
C15 C17 C18 119.0(4) . . ?
|
||||
C16 C17 C18 123.2(4) . . ?
|
||||
N1 C18 C17 109.0(3) 2 . ?
|
||||
N1 C18 H18A 109.9 2 . ?
|
||||
C17 C18 H18A 109.9 . . ?
|
||||
N1 C18 H18B 109.9 2 . ?
|
||||
C17 C18 H18B 109.9 . . ?
|
||||
H18A C18 H18B 108.3 . . ?
|
||||
N3 C19 C20 105.0(4) . . ?
|
||||
N3 C19 H19 127.5 . . ?
|
||||
C20 C19 H19 127.5 . . ?
|
||||
C19 C20 N5 108.7(4) . . ?
|
||||
C19 C20 C21 129.7(4) . . ?
|
||||
N5 C20 C21 121.6(5) . . ?
|
||||
O1 C21 C20 113.0(4) . . ?
|
||||
O1 C21 H21A 109.0 . . ?
|
||||
C20 C21 H21A 109.0 . . ?
|
||||
O1 C21 H21B 109.0 . . ?
|
||||
C20 C21 H21B 109.0 . . ?
|
||||
H21A C21 H21B 107.8 . . ?
|
||||
O1 C22 C23 109.1(4) . . ?
|
||||
O1 C22 H22A 109.9 . . ?
|
||||
C23 C22 H22A 109.9 . . ?
|
||||
O1 C22 H22B 109.9 . . ?
|
||||
C23 C22 H22B 109.9 . . ?
|
||||
H22A C22 H22B 108.3 . . ?
|
||||
O2 C23 C22 108.0(5) . . ?
|
||||
O2 C23 H23A 110.1 . . ?
|
||||
C22 C23 H23A 110.1 . . ?
|
||||
O2 C23 H23B 110.1 . . ?
|
||||
C22 C23 H23B 110.1 . . ?
|
||||
H23A C23 H23B 108.4 . . ?
|
||||
O2 C24 C25 110.9(6) . . ?
|
||||
O2 C24 H24A 109.5 . . ?
|
||||
C25 C24 H24A 109.5 . . ?
|
||||
O2 C24 H24B 109.5 . . ?
|
||||
C25 C24 H24B 109.5 . . ?
|
||||
H24A C24 H24B 108.0 . . ?
|
||||
O3 C25 C24 112.1(6) . . ?
|
||||
O3 C25 H25A 109.2 . . ?
|
||||
C24 C25 H25A 109.2 . . ?
|
||||
O3 C25 H25B 109.2 . . ?
|
||||
C24 C25 H25B 109.2 . . ?
|
||||
H25A C25 H25B 107.9 . . ?
|
||||
C27 C26 O3 98.8(7) . . ?
|
||||
C27 C26 H26A 112.0 . . ?
|
||||
O3 C26 H26A 112.0 . . ?
|
||||
C27 C26 H26B 112.0 . . ?
|
||||
O3 C26 H26B 112.0 . . ?
|
||||
H26A C26 H26B 109.7 . . ?
|
||||
C26 C27 O4 114.9(7) . . ?
|
||||
C26 C27 H27A 108.5 . . ?
|
||||
O4 C27 H27A 108.5 . . ?
|
||||
C26 C27 H27B 108.5 . . ?
|
||||
O4 C27 H27B 108.5 . . ?
|
||||
H27A C27 H27B 107.5 . . ?
|
||||
C29 C28 O4 124.1(6) . . ?
|
||||
C29 C28 H28A 106.3 . . ?
|
||||
O4 C28 H28A 106.3 . . ?
|
||||
C29 C28 H28B 106.3 . . ?
|
||||
O4 C28 H28B 106.3 . . ?
|
||||
H28A C28 H28B 106.4 . . ?
|
||||
C28 C29 O5 128.7(9) . . ?
|
||||
C28 C29 H29A 105.1 . . ?
|
||||
O5 C29 H29A 105.1 . . ?
|
||||
C28 C29 H29B 105.1 . . ?
|
||||
O5 C29 H29B 105.1 . . ?
|
||||
H29A C29 H29B 105.9 . . ?
|
||||
O5 C30 C31 110.9(6) . . ?
|
||||
O5 C30 H30A 109.5 . . ?
|
||||
C31 C30 H30A 109.5 . . ?
|
||||
O5 C30 H30B 109.5 . . ?
|
||||
C31 C30 H30B 109.5 . . ?
|
||||
H30A C30 H30B 108.1 . . ?
|
||||
O6 C31 C30 111.7(8) . . ?
|
||||
O6 C31 H31A 109.3 . . ?
|
||||
C30 C31 H31A 109.3 . . ?
|
||||
O6 C31 H31B 109.3 . . ?
|
||||
C30 C31 H31B 109.3 . . ?
|
||||
H31A C31 H31B 107.9 . . ?
|
||||
C33 C32 O6 108.1(6) . . ?
|
||||
C33 C32 H32A 110.1 . . ?
|
||||
O6 C32 H32A 110.1 . . ?
|
||||
C33 C32 H32B 110.1 . . ?
|
||||
O6 C32 H32B 110.1 . . ?
|
||||
H32A C32 H32B 108.4 . . ?
|
||||
C32 C33 O7 111.8(5) . . ?
|
||||
C32 C33 H33A 109.3 . . ?
|
||||
O7 C33 H33A 109.3 . . ?
|
||||
C32 C33 H33B 109.3 . . ?
|
||||
O7 C33 H33B 109.3 . . ?
|
||||
H33A C33 H33B 107.9 . . ?
|
||||
O7 C34 C35 124.0(4) . . ?
|
||||
O7 C34 C36 115.2(4) . . ?
|
||||
C35 C34 C36 120.8(4) . . ?
|
||||
C34 C35 C38 119.3(5) . 2 ?
|
||||
C34 C35 H35 120.4 . . ?
|
||||
C38 C35 H35 120.4 2 . ?
|
||||
C36 C36 C37 119.6(5) 2 . ?
|
||||
C36 C36 C34 118.4(5) 2 . ?
|
||||
C37 C36 C34 121.9(4) . . ?
|
||||
C38 C37 C36 119.9(4) . . ?
|
||||
C38 C37 H37 120.1 . . ?
|
||||
C36 C37 H37 120.1 . . ?
|
||||
C37 C38 C35 122.0(4) . 2 ?
|
||||
C37 C38 H38 119.0 . . ?
|
||||
C35 C38 H38 119.0 2 . ?
|
||||
C1 N1 C2 120.4(4) . . ?
|
||||
C1 N1 C18 120.5(4) . 2 ?
|
||||
C2 N1 C18 119.1(4) . 2 ?
|
||||
C9 N2 C10 120.6(4) . . ?
|
||||
C9 N2 C11 119.3(4) . . ?
|
||||
C10 N2 C11 119.9(4) . . ?
|
||||
C19 N3 N4 110.0(4) . . ?
|
||||
C19 N3 C16 130.4(4) . . ?
|
||||
N4 N3 C16 119.3(3) . . ?
|
||||
N5 N4 N3 107.0(3) . . ?
|
||||
N4 N5 C20 109.4(4) . . ?
|
||||
C22 O1 C21 112.0(4) . . ?
|
||||
C24 O2 C23 111.2(5) . . ?
|
||||
C25 O3 C26 101.1(6) . . ?
|
||||
C28 O4 C27 123.6(7) . . ?
|
||||
C29 O5 C30 109.4(11) . . ?
|
||||
C31 O6 C32 107.8(7) . . ?
|
||||
C34 O7 C33 116.5(4) . . ?
|
||||
O101 C101 O102 129.2(5) . . ?
|
||||
O101 C101 C102 113.1(5) . . ?
|
||||
O102 C101 C102 117.7(5) . . ?
|
||||
F103 C102 F102 108.6(7) . . ?
|
||||
F103 C102 F101 104.9(7) . . ?
|
||||
F102 C102 F101 105.0(7) . . ?
|
||||
F103 C102 C101 114.3(6) . . ?
|
||||
F102 C102 C101 112.4(5) . . ?
|
||||
F101 C102 C101 111.0(7) . . ?
|
||||
O104 C103 O103 130.2(5) . . ?
|
||||
O104 C103 C104 115.4(5) . . ?
|
||||
O103 C103 C104 114.3(5) . . ?
|
||||
F106 C104 F104 107.4(7) . . ?
|
||||
F106 C104 F105 99.1(9) . . ?
|
||||
F104 C104 F105 105.1(9) . . ?
|
||||
F106 C104 C103 115.6(8) . . ?
|
||||
F104 C104 C103 117.1(5) . . ?
|
||||
F105 C104 C103 110.5(7) . . ?
|
||||
N101 C105 C106 179.3(9) . . ?
|
||||
C105 C106 H10A 109.5 . . ?
|
||||
C105 C106 H10B 109.5 . . ?
|
||||
H10A C106 H10B 109.5 . . ?
|
||||
C105 C106 H10C 109.5 . . ?
|
||||
H10A C106 H10C 109.5 . . ?
|
||||
H10B C106 H10C 109.5 . . ?
|
||||
N102 C107 C108 179.3(14) . . ?
|
||||
C107 C108 H10D 109.5 . . ?
|
||||
C107 C108 H10E 109.5 . . ?
|
||||
H10D C108 H10E 109.5 . . ?
|
||||
C107 C108 H10F 109.5 . . ?
|
||||
H10D C108 H10F 109.5 . . ?
|
||||
H10E C108 H10F 109.5 . . ?
|
||||
|
||||
loop_
|
||||
_geom_torsion_atom_site_label_1
|
||||
_geom_torsion_atom_site_label_2
|
||||
_geom_torsion_atom_site_label_3
|
||||
_geom_torsion_atom_site_label_4
|
||||
_geom_torsion
|
||||
_geom_torsion_site_symmetry_1
|
||||
_geom_torsion_site_symmetry_2
|
||||
_geom_torsion_site_symmetry_3
|
||||
_geom_torsion_site_symmetry_4
|
||||
_geom_torsion_publ_flag
|
||||
N1 C1 C3 C5 0.3(6) . . . . ?
|
||||
N1 C2 C4 C5 1.1(6) . . . . ?
|
||||
C1 C3 C5 C4 3.1(6) . . . . ?
|
||||
C1 C3 C5 C6 -174.6(4) . . . . ?
|
||||
C2 C4 C5 C3 -3.8(5) . . . . ?
|
||||
C2 C4 C5 C6 173.9(3) . . . . ?
|
||||
C3 C5 C6 C8 -168.8(4) . . . . ?
|
||||
C4 C5 C6 C8 13.6(5) . . . . ?
|
||||
C3 C5 C6 C7 14.7(5) . . . . ?
|
||||
C4 C5 C6 C7 -162.9(4) . . . . ?
|
||||
C8 C6 C7 C9 -0.6(5) . . . . ?
|
||||
C5 C6 C7 C9 176.0(3) . . . . ?
|
||||
C7 C6 C8 C10 1.4(5) . . . . ?
|
||||
C5 C6 C8 C10 -175.2(3) . . . . ?
|
||||
C6 C7 C9 N2 -0.7(6) . . . . ?
|
||||
C6 C8 C10 N2 -0.8(6) . . . . ?
|
||||
N2 C11 C12 C14 88.4(5) . . . . ?
|
||||
N2 C11 C12 C13 -87.7(5) . . . . ?
|
||||
C14 C12 C13 C15 -5.7(6) . . . . ?
|
||||
C11 C12 C13 C15 170.4(4) . . . . ?
|
||||
C13 C12 C14 C16 4.9(6) . . . . ?
|
||||
C11 C12 C14 C16 -171.2(4) . . . . ?
|
||||
C12 C13 C15 C17 0.2(6) . . . . ?
|
||||
C12 C14 C16 C17 1.4(6) . . . . ?
|
||||
C12 C14 C16 N3 179.1(3) . . . . ?
|
||||
C13 C15 C17 C16 5.9(6) . . . . ?
|
||||
C13 C15 C17 C18 -167.5(4) . . . . ?
|
||||
C14 C16 C17 C15 -6.7(6) . . . . ?
|
||||
N3 C16 C17 C15 175.7(4) . . . . ?
|
||||
C14 C16 C17 C18 166.4(4) . . . . ?
|
||||
N3 C16 C17 C18 -11.2(6) . . . . ?
|
||||
C15 C17 C18 N1 83.8(5) . . . 2 ?
|
||||
C16 C17 C18 N1 -89.3(5) . . . 2 ?
|
||||
N3 C19 C20 N5 0.2(5) . . . . ?
|
||||
N3 C19 C20 C21 -179.5(5) . . . . ?
|
||||
C19 C20 C21 O1 78.8(7) . . . . ?
|
||||
N5 C20 C21 O1 -100.9(6) . . . . ?
|
||||
O1 C22 C23 O2 66.1(5) . . . . ?
|
||||
O2 C24 C25 O3 65.4(6) . . . . ?
|
||||
O3 C26 C27 O4 -86.2(9) . . . . ?
|
||||
O4 C28 C29 O5 -7(4) . . . . ?
|
||||
O5 C30 C31 O6 69.5(9) . . . . ?
|
||||
O6 C32 C33 O7 -71.5(8) . . . . ?
|
||||
O7 C34 C35 C38 -177.1(4) . . . 2 ?
|
||||
C36 C34 C35 C38 1.4(6) . . . 2 ?
|
||||
O7 C34 C36 C36 177.6(4) . . . 2 ?
|
||||
C35 C34 C36 C36 -1.1(7) . . . 2 ?
|
||||
O7 C34 C36 C37 -2.5(6) . . . . ?
|
||||
C35 C34 C36 C37 178.9(4) . . . . ?
|
||||
C36 C36 C37 C38 -0.8(7) 2 . . . ?
|
||||
C34 C36 C37 C38 179.2(4) . . . . ?
|
||||
C36 C37 C38 C35 0.5(6) . . . 2 ?
|
||||
C3 C1 N1 C2 -3.1(6) . . . . ?
|
||||
C3 C1 N1 C18 175.3(4) . . . 2 ?
|
||||
C4 C2 N1 C1 2.4(6) . . . . ?
|
||||
C4 C2 N1 C18 -176.0(3) . . . 2 ?
|
||||
C7 C9 N2 C10 1.4(6) . . . . ?
|
||||
C7 C9 N2 C11 -173.8(3) . . . . ?
|
||||
C8 C10 N2 C9 -0.6(6) . . . . ?
|
||||
C8 C10 N2 C11 174.5(3) . . . . ?
|
||||
C12 C11 N2 C9 85.7(4) . . . . ?
|
||||
C12 C11 N2 C10 -89.6(4) . . . . ?
|
||||
C20 C19 N3 N4 -0.2(5) . . . . ?
|
||||
C20 C19 N3 C16 -174.0(4) . . . . ?
|
||||
C14 C16 N3 C19 129.4(5) . . . . ?
|
||||
C17 C16 N3 C19 -52.9(6) . . . . ?
|
||||
C14 C16 N3 N4 -43.9(5) . . . . ?
|
||||
C17 C16 N3 N4 133.8(4) . . . . ?
|
||||
C19 N3 N4 N5 0.2(5) . . . . ?
|
||||
C16 N3 N4 N5 174.8(4) . . . . ?
|
||||
N3 N4 N5 C20 -0.1(5) . . . . ?
|
||||
C19 C20 N5 N4 -0.1(6) . . . . ?
|
||||
C21 C20 N5 N4 179.7(4) . . . . ?
|
||||
C23 C22 O1 C21 -171.9(4) . . . . ?
|
||||
C20 C21 O1 C22 63.3(6) . . . . ?
|
||||
C25 C24 O2 C23 170.3(5) . . . . ?
|
||||
C22 C23 O2 C24 164.7(4) . . . . ?
|
||||
C24 C25 O3 C26 170.9(5) . . . . ?
|
||||
C27 C26 O3 C25 177.5(7) . . . . ?
|
||||
C29 C28 O4 C27 -129(2) . . . . ?
|
||||
C26 C27 O4 C28 -85.6(11) . . . . ?
|
||||
C28 C29 O5 C30 136(3) . . . . ?
|
||||
C31 C30 O5 C29 177.4(11) . . . . ?
|
||||
C30 C31 O6 C32 178.6(7) . . . . ?
|
||||
C33 C32 O6 C31 -173.5(6) . . . . ?
|
||||
C35 C34 O7 C33 2.2(7) . . . . ?
|
||||
C36 C34 O7 C33 -176.4(5) . . . . ?
|
||||
C32 C33 O7 C34 169.3(6) . . . . ?
|
||||
O101 C101 C102 F103 -174.2(7) . . . . ?
|
||||
O102 C101 C102 F103 6.5(10) . . . . ?
|
||||
O101 C101 C102 F102 -49.8(9) . . . . ?
|
||||
O102 C101 C102 F102 130.9(7) . . . . ?
|
||||
O101 C101 C102 F101 67.5(7) . . . . ?
|
||||
O102 C101 C102 F101 -111.9(7) . . . . ?
|
||||
O104 C103 C104 F106 -34.8(12) . . . . ?
|
||||
O103 C103 C104 F106 149.3(9) . . . . ?
|
||||
O104 C103 C104 F104 -163.1(8) . . . . ?
|
||||
O103 C103 C104 F104 21.0(11) . . . . ?
|
||||
O104 C103 C104 F105 76.7(10) . . . . ?
|
||||
O103 C103 C104 F105 -99.2(8) . . . . ?
|
||||
|
||||
_diffrn_measured_fraction_theta_max 0.961
|
||||
_diffrn_reflns_theta_full 64.94
|
||||
_diffrn_measured_fraction_theta_full 0.961
|
||||
_refine_diff_density_max 1.693
|
||||
_refine_diff_density_min -0.992
|
||||
_refine_diff_density_rms 0.109
|
||||
|
||||
# start Validation Reply Form
|
||||
_vrf_PLAT213_I
|
||||
;
|
||||
PROBLEM: Atom C5 has ADP max/min Ratio ..... 5.1 oblat
|
||||
RESPONSE: The atoms of the glycol chain and of the CBPQT4+ ring showed elongated
|
||||
displacement parameters. Attempts to model this disorder did not significantly
|
||||
improve the refinement.
|
||||
;
|
||||
_vrf_PLAT222_I
|
||||
;
|
||||
PROBLEM: Large Non-Solvent H Uiso(max)/Uiso(min) .. 10.0 Ratio
|
||||
RESPONSE: Hydrogen atoms were refined as riding models with their isotropic
|
||||
displacement parameters linked to their parent atoms.
|
||||
In this case the parent atom exhibits disorder with an elongated
|
||||
displacement parameter and therefore the riding hydrogen atom is also large.
|
||||
;
|
||||
_vrf_PLAT241_I
|
||||
;
|
||||
PROBLEM: Check High Ueq as Compared to Neighbors for C27
|
||||
RESPONSE: C27 and C29 are part of the disordered glycol chain, however they
|
||||
are bonded to C26 and O5 which are relatively well-ordered parts of the
|
||||
structure.
|
||||
;
|
||||
|
||||
# end Validation Reply Form
|
||||
|
||||
|
||||
|
||||
39472
package-lock.json
generated
39472
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
158
package.json
158
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "0.2.2",
|
||||
"version": "3.0.0-dev.0",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -11,25 +11,48 @@
|
||||
"url": "https://github.com/molstar/molstar/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "tslint src/**/*.ts",
|
||||
"lint": "eslint .",
|
||||
"lint-fix": "eslint . --fix",
|
||||
"test": "npm run lint && jest",
|
||||
"jest": "jest",
|
||||
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
|
||||
"build-tsc": "tsc",
|
||||
"build-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html}\" lib/",
|
||||
"build-webpack": "webpack --mode production",
|
||||
"watch": "concurrently --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack\"",
|
||||
"watch-tsc": "tsc -watch",
|
||||
"watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html}\" lib/ --watch",
|
||||
"watch-webpack": "webpack -w --mode development --display minimal",
|
||||
"model-server": "node lib/servers/model/server.js",
|
||||
"model-server-watch": "nodemon --watch lib lib/servers/model/server.js",
|
||||
"build-viewer": "npm run build-tsc && npm run build-extra && npm run build-webpack-viewer",
|
||||
"build-tsc": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\"",
|
||||
"build-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/",
|
||||
"build-webpack": "webpack --mode production --config ./webpack.config.production.js",
|
||||
"build-webpack-viewer": "webpack --mode production --config ./webpack.config.viewer.js",
|
||||
"watch": "concurrently -c \"green,green,gray,gray\" --names \"tsc,srv,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-servers\" \"npm:watch-extra\" \"npm:watch-webpack\"",
|
||||
"watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"",
|
||||
"watch-viewer-debug": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer-debug\"",
|
||||
"watch-tsc": "tsc --watch --incremental",
|
||||
"watch-servers": "tsc --build tsconfig.commonjs.json --watch --incremental",
|
||||
"watch-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/ --watch",
|
||||
"watch-webpack": "webpack -w --mode development --stats minimal",
|
||||
"watch-webpack-viewer": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.js",
|
||||
"watch-webpack-viewer-debug": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.debug.js",
|
||||
"serve": "http-server -p 1338 -g",
|
||||
"model-server": "node lib/commonjs/servers/model/server.js",
|
||||
"model-server-watch": "nodemon --watch lib lib/commonjs/servers/model/server.js",
|
||||
"volume-server-test": "node lib/commonjs/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
|
||||
"plugin-state": "node lib/commonjs/servers/plugin-state/index.js --working-folder ./build/state --port 1339",
|
||||
"preversion": "npm run test",
|
||||
"postversion": "git push && git push --tags",
|
||||
"prepublishOnly": "npm run test && npm run build"
|
||||
"version": "npm run build",
|
||||
"postversion": "git push && git push --tags"
|
||||
},
|
||||
"files": [
|
||||
"lib/"
|
||||
"lib/",
|
||||
"build/viewer/"
|
||||
],
|
||||
"bin": {
|
||||
"cif2bcif": "lib/commonjs/cli/cif2bcif/index.js",
|
||||
"cifschema": "lib/commonjs/cli/cifschema/index.js",
|
||||
"model-server": "lib/commonjs/servers/model/server.js",
|
||||
"model-server-query": "lib/commonjs/servers/model/query.js",
|
||||
"model-server-preprocess": "lib/commonjs/servers/model/preprocess.js",
|
||||
"volume-server": "lib/commonjs/servers/volume/server.js",
|
||||
"volume-server-query": "lib/commonjs/servers/volume/query.js",
|
||||
"volume-server-pack": "lib/commonjs/servers/volume/pack.js"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"ignoreRoot": [
|
||||
"./node_modules",
|
||||
@@ -57,58 +80,79 @@
|
||||
"contributors": [
|
||||
"Alexander Rose <alexander.rose@weirdbyte.de>",
|
||||
"David Sehnal <david.sehnal@gmail.com>",
|
||||
"Sebastian Bittrich <sebastian.bittrich@rcsb.org>"
|
||||
"Sebastian Bittrich <sebastian.bittrich@rcsb.org>",
|
||||
"Áron Samuel Kovács <aron.kovacs@mail.muni.cz>",
|
||||
"Ludovic Autin <autin@scripps.edu>",
|
||||
"Michal Malý <michal.maly@ibt.cas.cz>",
|
||||
"Jiří Černý <jiri.cerny@ibt.cas.cz>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/add": "^3.1.0",
|
||||
"@graphql-codegen/cli": "^2.3.0",
|
||||
"@graphql-codegen/time": "^3.1.0",
|
||||
"@graphql-codegen/typescript": "^2.4.1",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^2.1.0",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.3.1",
|
||||
"@graphql-codegen/typescript-operations": "^2.2.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/gl": "^4.1.0",
|
||||
"@types/jest": "^27.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"circular-dependency-plugin": "^5.0.2",
|
||||
"concurrently": "^4.1.0",
|
||||
"cpx": "^1.5.0",
|
||||
"css-loader": "^2.1.1",
|
||||
"concurrently": "^6.4.0",
|
||||
"cpx2": "^4.0.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.5.1",
|
||||
"eslint": "^8.3.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^3.0.1",
|
||||
"graphql-code-generator": "^0.18.2",
|
||||
"graphql-codegen-time": "^0.18.2",
|
||||
"graphql-codegen-typescript-template": "^0.18.2",
|
||||
"jest": "^24.8.0",
|
||||
"jest-raw-loader": "^1.0.1",
|
||||
"mini-css-extract-plugin": "^0.7.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"raw-loader": "^2.0.0",
|
||||
"resolve-url-loader": "^3.1.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"ts-jest": "^24.0.2",
|
||||
"tslint": "^5.17.0",
|
||||
"typescript": "^3.5.1",
|
||||
"uglify-js": "^3.6.0",
|
||||
"util.promisify": "^1.0.0",
|
||||
"webpack": "^4.32.2",
|
||||
"webpack-cli": "^3.3.2"
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"graphql": "^15.7.2",
|
||||
"http-server": "^14.0.0",
|
||||
"jest": "^27.3.1",
|
||||
"mini-css-extract-plugin": "^2.4.5",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sass": "^1.43.5",
|
||||
"sass-loader": "^12.3.0",
|
||||
"simple-git": "^2.47.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-jest": "^27.0.7",
|
||||
"typescript": "^4.5.2",
|
||||
"webpack": "^5.64.4",
|
||||
"webpack-cli": "^4.9.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^1.0.36",
|
||||
"@types/benchmark": "^1.0.31",
|
||||
"@types/compression": "0.0.36",
|
||||
"@types/express": "^4.16.1",
|
||||
"@types/jest": "^24.0.13",
|
||||
"@types/node": "^12.0.4",
|
||||
"@types/node-fetch": "^2.3.4",
|
||||
"@types/react": "^16.8.19",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/swagger-ui-dist": "3.0.0",
|
||||
"@types/webgl2": "0.0.4",
|
||||
"argparse": "^1.0.10",
|
||||
"@types/argparse": "^2.0.10",
|
||||
"@types/benchmark": "^2.1.1",
|
||||
"@types/compression": "1.7.2",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/node": "^16.11.10",
|
||||
"@types/node-fetch": "^2.5.12",
|
||||
"@types/react": "^17.0.37",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"@types/swagger-ui-dist": "3.30.1",
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.19.0",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"graphql": "^14.3.1",
|
||||
"h264-mp4-encoder": "^1.0.12",
|
||||
"immer": "^9.0.7",
|
||||
"immutable": "^3.8.2",
|
||||
"node-fetch": "^2.6.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"rxjs": "^6.5.2",
|
||||
"swagger-ui-dist": "^3.22.2",
|
||||
"xhr2": "^0.2.0"
|
||||
"node-fetch": "^2.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"rxjs": "^7.4.0",
|
||||
"swagger-ui-dist": "^4.1.1",
|
||||
"tslib": "^2.3.1",
|
||||
"util.promisify": "^1.1.1",
|
||||
"xhr2": "^0.2.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"gl": "^4.9.2"
|
||||
}
|
||||
}
|
||||
|
||||
59
scripts/deploy.js
Normal file
59
scripts/deploy.js
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
const git = require('simple-git');
|
||||
const path = require('path');
|
||||
const fs = require("fs");
|
||||
const fse = require("fs-extra");
|
||||
|
||||
const remoteUrl = "https://github.com/molstar/molstar.github.io.git";
|
||||
const buildDir = path.resolve(__dirname, '../build/');
|
||||
const deployDir = path.resolve(buildDir, 'deploy/');
|
||||
const localPath = path.resolve(deployDir, 'molstar.github.io/');
|
||||
|
||||
function log(command, stdout, stderr) {
|
||||
if (command) {
|
||||
console.log('\n###', command);
|
||||
stdout.pipe(process.stdout);
|
||||
stderr.pipe(process.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
function copyViewer() {
|
||||
console.log('\n###', 'copy viewer files');
|
||||
const viewerBuildPath = path.resolve(buildDir, '../build/viewer/');
|
||||
const viewerDeployPath = path.resolve(localPath, 'viewer/');
|
||||
fse.copySync(viewerBuildPath, viewerDeployPath, { overwrite: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(localPath)) {
|
||||
console.log('\n###', 'create localPath');
|
||||
fs.mkdirSync(localPath, { recursive: true });
|
||||
}
|
||||
|
||||
process.chdir(localPath);
|
||||
|
||||
if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
|
||||
console.log('\n###', 'clone repository');
|
||||
git()
|
||||
.outputHandler(log)
|
||||
.clone(remoteUrl, localPath)
|
||||
.fetch(['--all'])
|
||||
.exec(copyViewer)
|
||||
.add(['-A'])
|
||||
.commit('updated viewer')
|
||||
.push();
|
||||
} else {
|
||||
console.log('\n###', 'update repository');
|
||||
git()
|
||||
.outputHandler(log)
|
||||
.fetch(['--all'])
|
||||
.reset(['--hard', 'origin/master'])
|
||||
.exec(copyViewer)
|
||||
.add(['-A'])
|
||||
.commit('updated viewer')
|
||||
.push();
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { PluginUIComponent } from '../../mol-plugin/ui/base';
|
||||
import * as React from 'react';
|
||||
import { TransformUpdaterControl } from '../../mol-plugin/ui/state/update-transform';
|
||||
|
||||
export class BasicWrapperControls extends PluginUIComponent {
|
||||
|
||||
render() {
|
||||
return <div style={{ overflowY: 'auto', display: 'block', height: '100%' }}>
|
||||
<TransformUpdaterControl nodeRef='asm' />
|
||||
<TransformUpdaterControl nodeRef='seq-visual' header={{ name: 'Sequence Visual' }} />
|
||||
<TransformUpdaterControl nodeRef='het-visual' header={{ name: 'HET Visual' }} />
|
||||
<TransformUpdaterControl nodeRef='water-visual' header={{ name: 'Water Visual' }} initiallyCollapsed={true} />
|
||||
<TransformUpdaterControl nodeRef='ihm-visual' header={{ name: 'I/HM Visual' }} initiallyCollapsed={true} />
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin/state/transforms';
|
||||
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { StateBuilder } from '../../mol-state';
|
||||
import Expression from '../../mol-script/language/expression';
|
||||
import { BuiltInColorThemeName } from '../../mol-theme/color';
|
||||
type SupportedFormats = 'cif' | 'pdb'
|
||||
|
||||
export namespace StateHelper {
|
||||
export function download(b: StateBuilder.To<PSO.Root>, url: string, ref?: string) {
|
||||
return b.apply(StateTransforms.Data.Download, { url, isBinary: false }, { ref });
|
||||
}
|
||||
|
||||
export function getModel(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, modelIndex = 0) {
|
||||
const parsed = format === 'cif'
|
||||
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
|
||||
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
|
||||
|
||||
return parsed.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex });
|
||||
}
|
||||
|
||||
export function structure(b: StateBuilder.To<PSO.Molecule.Model>) {
|
||||
return b.apply(StateTransforms.Model.StructureFromModel, { tags: 'structure' })
|
||||
};
|
||||
|
||||
export function selectChain(b: StateBuilder.To<PSO.Molecule.Structure>, auth_asym_id: string) {
|
||||
const query = MS.struct.generator.atomGroups({
|
||||
'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), auth_asym_id])
|
||||
})
|
||||
return b.apply(StateTransforms.Model.StructureSelection, { query, label: `Chain ${auth_asym_id}` });
|
||||
}
|
||||
|
||||
export function select(b: StateBuilder.To<PSO.Molecule.Structure>, query: Expression) {
|
||||
return b.apply(StateTransforms.Model.StructureSelection, { query });
|
||||
}
|
||||
|
||||
export function selectSurroundingsOfFirstResidue(b: StateBuilder.To<PSO.Molecule.Structure>, comp_id: string, radius: number) {
|
||||
const query = MS.struct.modifier.includeSurroundings({
|
||||
0: MS.struct.filter.first([
|
||||
MS.struct.generator.atomGroups({
|
||||
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
|
||||
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
|
||||
})
|
||||
]),
|
||||
radius
|
||||
})
|
||||
return b.apply(StateTransforms.Model.StructureSelection, { query, label: `Surr. ${comp_id} (${radius} ang)` });
|
||||
}
|
||||
|
||||
export function identityTransform(b: StateBuilder.To<PSO.Molecule.Structure>, m: Mat4) {
|
||||
return b.apply(StateTransforms.Model.TransformStructureConformation,
|
||||
{ axis: Vec3.create(1, 0, 0), angle: 0, translation: Vec3.zero() },
|
||||
{ tags: 'transform' });
|
||||
}
|
||||
|
||||
export function transform(b: StateBuilder.To<PSO.Molecule.Structure>, matrix: Mat4) {
|
||||
return b.apply(StateTransforms.Model.TransformStructureConformationByMatrix, { matrix }, { tags: 'transform' });
|
||||
}
|
||||
|
||||
export function assemble(b: StateBuilder.To<PSO.Molecule.Model>, id?: string) {
|
||||
return b.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: id || 'deposited' }, { tags: 'asm' })
|
||||
}
|
||||
|
||||
export function visual(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon'), { tags: 'seq-visual' });
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick'), { tags: 'het-visual' });
|
||||
// visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
|
||||
// .apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
// StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 }), { tags: 'water-visual' });
|
||||
return visualRoot;
|
||||
}
|
||||
|
||||
export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, query: Expression, coloring?: BuiltInColorThemeName) {
|
||||
visualRoot
|
||||
.apply(StateTransforms.Model.StructureSelection, { query })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', void 0, coloring), { tags: 'het-visual' });
|
||||
return visualRoot;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
|
||||
import './index.html'
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { PluginCommands } from '../../mol-plugin/command';
|
||||
import { StateTransforms } from '../../mol-plugin/state/transforms';
|
||||
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
|
||||
import { AnimateModelIndex } from '../../mol-plugin/state/animation/built-in';
|
||||
import { StateBuilder, StateTransform } from '../../mol-state';
|
||||
import { StripedResidues } from './coloring';
|
||||
// import { BasicWrapperControls } from './controls';
|
||||
import { StaticSuperpositionTestData, buildStaticSuperposition, dynamicSuperpositionTest } from './superposition';
|
||||
require('mol-plugin/skin/light.scss')
|
||||
|
||||
type SupportedFormats = 'cif' | 'pdb'
|
||||
type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
|
||||
|
||||
class BasicWrapper {
|
||||
plugin: PluginContext;
|
||||
|
||||
init(target: string | HTMLElement) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginSpec,
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: false,
|
||||
showControls: false
|
||||
},
|
||||
controls: {
|
||||
// left: 'none',
|
||||
// right: BasicWrapperControls
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.Descriptor.name, StripedResidues.colorTheme!);
|
||||
this.plugin.lociLabels.addProvider(StripedResidues.labelProvider);
|
||||
this.plugin.customModelProperties.register(StripedResidues.propertyProvider);
|
||||
}
|
||||
|
||||
private download(b: StateBuilder.To<PSO.Root>, url: string) {
|
||||
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
|
||||
}
|
||||
|
||||
private parse(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
|
||||
const parsed = format === 'cif'
|
||||
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
|
||||
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
|
||||
|
||||
return parsed
|
||||
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
|
||||
.apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.Descriptor.name] }, { ref: 'props', state: { isGhost: false } })
|
||||
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
|
||||
}
|
||||
|
||||
private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'), { ref: 'seq-visual' });
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'), { ref: 'het-visual' });
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick', { alpha: 0.51 }), { ref: 'water-visual' });
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill'), { ref: 'ihm-visual' });
|
||||
return visualRoot;
|
||||
}
|
||||
|
||||
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
|
||||
async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
|
||||
let loadType: 'full' | 'update' = 'full';
|
||||
|
||||
const state = this.plugin.state.dataState;
|
||||
|
||||
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
|
||||
loadType = 'full';
|
||||
} else if (this.loadedParams.url === url) {
|
||||
if (state.select('asm').length > 0) loadType = 'update';
|
||||
}
|
||||
|
||||
let tree: StateBuilder.Root;
|
||||
if (loadType === 'full') {
|
||||
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
|
||||
tree = state.build();
|
||||
this.visual(this.parse(this.download(tree.toRoot(), url), format, assemblyId));
|
||||
} else {
|
||||
tree = state.build();
|
||||
tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
|
||||
}
|
||||
|
||||
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
|
||||
this.loadedParams = { url, format, assemblyId };
|
||||
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
|
||||
}
|
||||
|
||||
setBackground(color: number) {
|
||||
const renderer = this.plugin.canvas3d.props.renderer;
|
||||
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
|
||||
}
|
||||
|
||||
toggleSpin() {
|
||||
const trackball = this.plugin.canvas3d.props.trackball;
|
||||
const spinning = trackball.spin;
|
||||
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
|
||||
if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
|
||||
}
|
||||
|
||||
animate = {
|
||||
modelIndex: {
|
||||
maxFPS: 8,
|
||||
onceForward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'forward' } } }) },
|
||||
onceBackward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'backward' } } }) },
|
||||
palindrome: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'palindrome', params: {} } }) },
|
||||
loop: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'loop', params: {} } }) },
|
||||
stop: () => this.plugin.state.animation.stop()
|
||||
}
|
||||
}
|
||||
|
||||
coloring = {
|
||||
applyStripes: async () => {
|
||||
const state = this.plugin.state.dataState;
|
||||
|
||||
const visuals = state.selectQ(q => q.ofTransformer(StateTransforms.Representation.StructureRepresentation3D));
|
||||
const tree = state.build();
|
||||
const colorTheme = { name: StripedResidues.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(StripedResidues.Descriptor.name).defaultValues };
|
||||
|
||||
for (const v of visuals) {
|
||||
tree.to(v).update(old => ({ ...old, colorTheme }));
|
||||
}
|
||||
|
||||
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
|
||||
}
|
||||
}
|
||||
|
||||
tests = {
|
||||
staticSuperposition: async () => {
|
||||
const state = this.plugin.state.dataState;
|
||||
const tree = buildStaticSuperposition(this.plugin, StaticSuperpositionTestData);
|
||||
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: StateTransform.RootRef });
|
||||
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
|
||||
},
|
||||
dynamicSuperposition: async () => {
|
||||
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.plugin.state.dataState, ref: StateTransform.RootRef });
|
||||
await dynamicSuperpositionTest(this.plugin, ['1tqn', '2hhb', '4hhb'], 'HEM');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(window as any).BasicMolStarWrapper = new BasicWrapper();
|
||||
@@ -1,108 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
// TODO: move to an "example"
|
||||
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { Mat4 } from '../../mol-math/linear-algebra';
|
||||
import { StateHelper } from './helpers';
|
||||
import { PluginCommands } from '../../mol-plugin/command';
|
||||
import { StateSelection, StateBuilder } from '../../mol-state';
|
||||
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { compile } from '../../mol-script/runtime/query/compiler';
|
||||
import { StructureSelection, QueryContext } from '../../mol-model/structure';
|
||||
import { superposeStructures } from '../../mol-model/structure/structure/util/superposition';
|
||||
import Expression from '../../mol-script/language/expression';
|
||||
|
||||
export type SuperpositionTestInput = {
|
||||
pdbId: string,
|
||||
auth_asym_id: string,
|
||||
matrix: Mat4
|
||||
}[];
|
||||
|
||||
// function getAxisAngleTranslation(m: Mat4) {
|
||||
// const translation = Mat4.getTranslation(Vec3.zero(), m);
|
||||
// const axis = Vec3.zero();
|
||||
// const angle = 180 / Math.PI * Quat.getAxisAngle(axis, Mat4.getRotation(Quat.zero(), m));
|
||||
// return { translation, axis, angle };
|
||||
// }
|
||||
|
||||
export function buildStaticSuperposition(ctx: PluginContext, src: SuperpositionTestInput) {
|
||||
const b = ctx.state.dataState.build().toRoot();
|
||||
for (const s of src) {
|
||||
StateHelper.visual(ctx,
|
||||
StateHelper.transform(
|
||||
StateHelper.selectChain(
|
||||
StateHelper.structure(
|
||||
StateHelper.getModel(StateHelper.download(b, `https://www.ebi.ac.uk/pdbe/static/entry/${s.pdbId}_updated.cif`), 'cif')),
|
||||
s.auth_asym_id
|
||||
),
|
||||
s.matrix
|
||||
)
|
||||
);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
export const StaticSuperpositionTestData: SuperpositionTestInput = [
|
||||
{ pdbId: '1aj5', auth_asym_id: 'A', matrix: Mat4.identity() },
|
||||
{ pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows(
|
||||
[[0.406, 0.879, 0.248, -200.633],
|
||||
[0.693, -0.473, 0.544, 73.403],
|
||||
[0.596, -0.049, -0.802, -14.209],
|
||||
[0, 0, 0, 1]] )},
|
||||
{ pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows(
|
||||
[[-0.053, -0.077, 0.996, -45.633],
|
||||
[-0.312, 0.949, 0.057, -12.255],
|
||||
[-0.949, -0.307, -0.074, 53.562],
|
||||
[0, 0, 0, 1]] )}
|
||||
];
|
||||
|
||||
export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[], comp_id: string) {
|
||||
const state = ctx.state.dataState;
|
||||
|
||||
const structures = state.build().toRoot();
|
||||
for (const s of src) {
|
||||
StateHelper.structure(
|
||||
StateHelper.getModel(StateHelper.download(structures, `https://www.ebi.ac.uk/pdbe/static/entry/${s}_updated.cif`), 'cif'));
|
||||
}
|
||||
|
||||
await PluginCommands.State.Update.dispatch(ctx, { state, tree: structures });
|
||||
|
||||
const pivot = MS.struct.filter.first([
|
||||
MS.struct.generator.atomGroups({
|
||||
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
|
||||
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
|
||||
})
|
||||
]);
|
||||
const rest = MS.struct.modifier.exceptBy({
|
||||
0: MS.struct.generator.all(),
|
||||
by: pivot
|
||||
});
|
||||
|
||||
const query = compile<StructureSelection>(pivot);
|
||||
const xs = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure));
|
||||
const selections = xs.map(s => StructureSelection.toLoci(query(new QueryContext(s.obj!.data))));
|
||||
|
||||
const transforms = superposeStructures(selections);
|
||||
const visuals = state.build();
|
||||
|
||||
siteVisual(ctx, StateHelper.selectSurroundingsOfFirstResidue(visuals.to(xs[0].transform.ref), 'HEM', 7), pivot, rest);
|
||||
for (let i = 1; i < selections.length; i++) {
|
||||
const root = visuals.to(xs[i].transform.ref);
|
||||
siteVisual(ctx,
|
||||
StateHelper.transform(StateHelper.selectSurroundingsOfFirstResidue(root, 'HEM', 7), transforms[i - 1].bTransform),
|
||||
pivot, rest);
|
||||
}
|
||||
|
||||
await PluginCommands.State.Update.dispatch(ctx, { state, tree: visuals });
|
||||
}
|
||||
|
||||
function siteVisual(ctx: PluginContext, b: StateBuilder.To<PSO.Molecule.Structure>, pivot: Expression, rest: Expression) {
|
||||
StateHelper.ballsAndSticks(ctx, b, pivot, 'residue-name');
|
||||
StateHelper.ballsAndSticks(ctx, b, rest, 'uniform');
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse'
|
||||
import * as util from 'util'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import * as zlib from 'zlib'
|
||||
import fetch from 'node-fetch'
|
||||
require('util.promisify').shim()
|
||||
const readFile = util.promisify(fs.readFile)
|
||||
const writeFile = util.promisify(fs.writeFile)
|
||||
|
||||
import { Progress } from '../../mol-task'
|
||||
import { Database, Table, DatabaseCollection, Column } from '../../mol-data/db'
|
||||
import { CIF } from '../../mol-io/reader/cif'
|
||||
import { CifWriter } from '../../mol-io/writer/cif'
|
||||
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd'
|
||||
import { SetUtils } from '../../mol-util/set'
|
||||
import { DefaultMap } from '../../mol-util/map'
|
||||
|
||||
export async function ensureAvailable(path: string, url: string) {
|
||||
if (FORCE_DOWNLOAD || !fs.existsSync(path)) {
|
||||
console.log(`downloading ${url}...`)
|
||||
const data = await fetch(url)
|
||||
if (!fs.existsSync(DATA_DIR)) {
|
||||
fs.mkdirSync(DATA_DIR);
|
||||
}
|
||||
if (url.endsWith('.gz')) {
|
||||
await writeFile(path, zlib.gunzipSync(await data.buffer()))
|
||||
} else {
|
||||
await writeFile(path, await data.text())
|
||||
}
|
||||
console.log(`done downloading ${url}`)
|
||||
}
|
||||
}
|
||||
|
||||
export async function ensureDataAvailable() {
|
||||
await ensureAvailable(CCD_PATH, CCD_URL)
|
||||
await ensureAvailable(PVCD_PATH, PVCD_URL)
|
||||
}
|
||||
|
||||
export async function readFileAsCollection<S extends Database.Schema>(path: string, schema: S) {
|
||||
const parsed = await parseCif(await readFile(path, 'utf8'))
|
||||
return CIF.toDatabaseCollection(schema, parsed.result)
|
||||
}
|
||||
|
||||
export async function readCCD() {
|
||||
return readFileAsCollection(CCD_PATH, CCD_Schema)
|
||||
}
|
||||
|
||||
export async function readPVCD() {
|
||||
return readFileAsCollection(PVCD_PATH, CCD_Schema)
|
||||
}
|
||||
|
||||
async function parseCif(data: string | Uint8Array) {
|
||||
const comp = CIF.parse(data);
|
||||
console.time('parse cif');
|
||||
const parsed = await comp.run(p => console.log(Progress.format(p)), 250);
|
||||
console.timeEnd('parse cif');
|
||||
if (parsed.isError) throw parsed;
|
||||
return parsed
|
||||
}
|
||||
|
||||
export function getEncodedCif(name: string, database: Database<Database.Schema>, binary = false) {
|
||||
const encoder = CifWriter.createEncoder({ binary, encoderName: 'mol*' });
|
||||
CifWriter.Encoder.writeDatabase(encoder, name, database)
|
||||
return encoder.getData();
|
||||
}
|
||||
|
||||
type CCB = Table<CCD_Schema['chem_comp_bond']>
|
||||
type CCA = Table<CCD_Schema['chem_comp_atom']>
|
||||
|
||||
const ChemCompBond_Schema = {
|
||||
comp_id: CCD_Schema['chem_comp_bond'].comp_id,
|
||||
atom_id_1: CCD_Schema['chem_comp_bond'].atom_id_1,
|
||||
atom_id_2: CCD_Schema['chem_comp_bond'].atom_id_2,
|
||||
value_order: CCD_Schema['chem_comp_bond'].value_order,
|
||||
pdbx_aromatic_flag: CCD_Schema['chem_comp_bond'].pdbx_aromatic_flag,
|
||||
pdbx_stereo_config: CCD_Schema['chem_comp_bond'].pdbx_stereo_config,
|
||||
molstar_protonation_variant: Column.Schema.Str()
|
||||
}
|
||||
|
||||
function ccbKey(compId: string, atomId1: string, atomId2: string) {
|
||||
return atomId1 < atomId2 ? `${compId}:${atomId1}-${atomId2}` : `${compId}:${atomId2}-${atomId1}`
|
||||
}
|
||||
|
||||
function addChemCompBondToSet(set: Set<string>, ccb: CCB) {
|
||||
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
|
||||
set.add(ccbKey(ccb.comp_id.value(i), ccb.atom_id_1.value(i), ccb.atom_id_2.value(i)))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
function addChemCompAtomToSet(set: Set<string>, cca: CCA) {
|
||||
for (let i = 0, il = cca._rowCount; i < il; ++i) {
|
||||
set.add(cca.atom_id.value(i))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
function checkAddingBondsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
|
||||
const ccbSetByParent = DefaultMap<string, Set<string>>(() => new Set())
|
||||
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_bond } = pvcd[k]
|
||||
if (chem_comp_bond._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0)
|
||||
if (parentIds.length === 0) {
|
||||
const set = ccbSetByParent.getDefault(chem_comp.id.value(0))
|
||||
addChemCompBondToSet(set, chem_comp_bond)
|
||||
} else {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
const parentId = parentIds[i]
|
||||
const set = ccbSetByParent.getDefault(parentId)
|
||||
addChemCompBondToSet(set, chem_comp_bond)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_atom, chem_comp_bond } = pvcd[k]
|
||||
if (chem_comp_bond._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0)
|
||||
if (parentIds.length > 0) {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
const entryBonds = addChemCompBondToSet(new Set<string>(), chem_comp_bond)
|
||||
const entryAtoms = addChemCompAtomToSet(new Set<string>(), chem_comp_atom)
|
||||
const extraBonds = SetUtils.difference(ccbSetByParent.get(parentIds[i])!, entryBonds)
|
||||
extraBonds.forEach(bk => {
|
||||
const [a1, a2] = bk.split('|')
|
||||
if (entryAtoms.has(a1) && entryAtoms.has(a2)) {
|
||||
console.error(`Adding all PVCD bonds would wrongly add bond ${bk} for ${k}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createBonds() {
|
||||
await ensureDataAvailable()
|
||||
const ccd = await readCCD()
|
||||
const pvcd = await readPVCD()
|
||||
|
||||
const ccbSet = new Set<string>()
|
||||
|
||||
const comp_id: string[] = []
|
||||
const atom_id_1: string[] = []
|
||||
const atom_id_2: string[] = []
|
||||
const value_order: string[] = []
|
||||
const pdbx_aromatic_flag: string[] = []
|
||||
const pdbx_stereo_config: string[] = []
|
||||
const molstar_protonation_variant: string[] = []
|
||||
|
||||
function addBonds(compId: string, ccb: CCB, protonationVariant: boolean) {
|
||||
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
|
||||
const atomId1 = ccb.atom_id_1.value(i)
|
||||
const atomId2 = ccb.atom_id_2.value(i)
|
||||
const k = ccbKey(compId, atomId1, atomId2)
|
||||
if (!ccbSet.has(k)) {
|
||||
atom_id_1.push(atomId1)
|
||||
atom_id_2.push(atomId2)
|
||||
comp_id.push(compId)
|
||||
value_order.push(ccb.value_order.value(i))
|
||||
pdbx_aromatic_flag.push(ccb.pdbx_aromatic_flag.value(i))
|
||||
pdbx_stereo_config.push(ccb.pdbx_stereo_config.value(i))
|
||||
molstar_protonation_variant.push(protonationVariant ? 'Y' : 'N')
|
||||
ccbSet.add(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check adding bonds from PVCD
|
||||
checkAddingBondsFromPVCD(pvcd)
|
||||
|
||||
// add bonds from PVCD
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_bond } = pvcd[k]
|
||||
if (chem_comp_bond._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0)
|
||||
if (parentIds.length === 0) {
|
||||
addBonds(chem_comp.id.value(0), chem_comp_bond, false)
|
||||
} else {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
addBonds(parentIds[i], chem_comp_bond, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add bonds from CCD
|
||||
for (const k in ccd) {
|
||||
const { chem_comp, chem_comp_bond } = ccd[k]
|
||||
if (chem_comp_bond._rowCount) {
|
||||
addBonds(chem_comp.id.value(0), chem_comp_bond, false)
|
||||
}
|
||||
}
|
||||
|
||||
const bondTable = Table.ofArrays(ChemCompBond_Schema, {
|
||||
comp_id, atom_id_1, atom_id_2, value_order,
|
||||
pdbx_aromatic_flag, pdbx_stereo_config, molstar_protonation_variant
|
||||
})
|
||||
|
||||
const bondDatabase = Database.ofTables(
|
||||
TABLE_NAME,
|
||||
{ chem_comp_bond: ChemCompBond_Schema },
|
||||
{ chem_comp_bond: bondTable }
|
||||
)
|
||||
|
||||
return bondDatabase
|
||||
}
|
||||
|
||||
async function run(out: string, binary = false) {
|
||||
const bonds = await createBonds()
|
||||
|
||||
const cif = getEncodedCif(TABLE_NAME, bonds, binary)
|
||||
writeFile(out, cif)
|
||||
}
|
||||
|
||||
const TABLE_NAME = 'CHEM_COMP_BONDS'
|
||||
|
||||
const DATA_DIR = path.join(__dirname, '..', '..', '..', 'data')
|
||||
const CCD_PATH = path.join(DATA_DIR, 'components.cif')
|
||||
const PVCD_PATH = path.join(DATA_DIR, 'aa-variants-v1.cif')
|
||||
const CCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif'
|
||||
const PVCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/aa-variants-v1.cif'
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
description: 'Create a cif file with one big table of all chem_comp_bond entries from the CCD and PVCD.'
|
||||
});
|
||||
parser.addArgument('out', {
|
||||
help: 'Generated file output path.'
|
||||
});
|
||||
parser.addArgument([ '--forceDownload', '-f' ], {
|
||||
action: 'storeTrue',
|
||||
help: 'Force download of CCD and PVCD.'
|
||||
});
|
||||
parser.addArgument([ '--binary', '-b' ], {
|
||||
action: 'storeTrue',
|
||||
help: 'Output as BinaryCIF.'
|
||||
});
|
||||
interface Args {
|
||||
out: string
|
||||
forceDownload?: boolean
|
||||
binary?: boolean
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
|
||||
const FORCE_DOWNLOAD = args.forceDownload
|
||||
|
||||
run(args.out, args.binary)
|
||||
37
src/apps/docking-viewer/index.html
Normal file
37
src/apps/docking-viewer/index.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<title>Mol* Docking Viewer</title>
|
||||
<style>
|
||||
#app {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="./molstar.js"></script>
|
||||
<script type="text/javascript">
|
||||
var viewer = new DockingViewer('app', [0x33DD22, 0x1133EE], true);
|
||||
|
||||
function getParam(name, regex) {
|
||||
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
|
||||
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
|
||||
}
|
||||
var pdbqt = getParam('pdbqt', '[^&]+').trim();
|
||||
var mol2 = getParam('mol2', '[^&]+').trim();
|
||||
|
||||
viewer.loadStructuresFromUrlsAndMerge([
|
||||
{ url: pdbqt, format: 'pdbqt' },
|
||||
{ url: mol2, format: 'mol2' }
|
||||
]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
213
src/apps/docking-viewer/index.ts
Normal file
213
src/apps/docking-viewer/index.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Structure } from '../../mol-model/structure';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { PluginStateObject as PSO, PluginStateTransform } from '../../mol-plugin-state/objects';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
|
||||
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginBehaviors } from '../../mol-plugin/behavior';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { PluginSpec } from '../../mol-plugin/spec';
|
||||
import { StateObject } from '../../mol-state';
|
||||
import { Task } from '../../mol-task';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import '../../mol-util/polyfill';
|
||||
import { ObjectKeys } from '../../mol-util/type-helpers';
|
||||
import './index.html';
|
||||
import { ShowButtons, StructurePreset, ViewportComponent } from './viewport';
|
||||
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
|
||||
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
|
||||
export { setDebugMode, setProductionMode } from '../../mol-util/debug';
|
||||
export { Viewer as DockingViewer };
|
||||
|
||||
const DefaultViewerOptions = {
|
||||
extensions: ObjectKeys({}),
|
||||
layoutIsExpanded: true,
|
||||
layoutShowControls: true,
|
||||
layoutShowRemoteState: true,
|
||||
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: true,
|
||||
layoutShowLeftPanel: true,
|
||||
|
||||
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
|
||||
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
|
||||
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
|
||||
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
|
||||
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
|
||||
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
|
||||
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
|
||||
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
|
||||
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
|
||||
};
|
||||
|
||||
class Viewer {
|
||||
plugin: PluginUIContext
|
||||
|
||||
constructor(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
|
||||
const o = { ...DefaultViewerOptions, ...{
|
||||
layoutIsExpanded: false,
|
||||
layoutShowControls: false,
|
||||
layoutShowRemoteState: false,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: false,
|
||||
layoutShowLeftPanel: true,
|
||||
|
||||
viewportShowExpand: true,
|
||||
viewportShowControls: false,
|
||||
viewportShowSettings: false,
|
||||
viewportShowSelectionMode: false,
|
||||
viewportShowAnimation: false,
|
||||
} };
|
||||
const defaultSpec = DefaultPluginUISpec();
|
||||
|
||||
const spec: PluginUISpec = {
|
||||
actions: defaultSpec.actions,
|
||||
behaviors: [
|
||||
PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci, { mark: false }),
|
||||
PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
|
||||
PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci),
|
||||
|
||||
PluginSpec.Behavior(PluginBehaviors.CustomProps.StructureInfo),
|
||||
PluginSpec.Behavior(PluginBehaviors.CustomProps.Interactions),
|
||||
PluginSpec.Behavior(PluginBehaviors.CustomProps.SecondaryStructure),
|
||||
],
|
||||
animations: defaultSpec.animations,
|
||||
customParamEditors: defaultSpec.customParamEditors,
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: o.layoutIsExpanded,
|
||||
showControls: o.layoutShowControls,
|
||||
controlsDisplay: o.layoutControlsDisplay,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
...defaultSpec.components,
|
||||
controls: {
|
||||
...defaultSpec.components?.controls,
|
||||
top: o.layoutShowSequence ? undefined : 'none',
|
||||
bottom: o.layoutShowLog ? undefined : 'none',
|
||||
left: o.layoutShowLeftPanel ? undefined : 'none',
|
||||
},
|
||||
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
|
||||
viewport: {
|
||||
view: ViewportComponent
|
||||
}
|
||||
},
|
||||
config: [
|
||||
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
|
||||
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
|
||||
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
|
||||
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
|
||||
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
|
||||
[PluginConfig.State.DefaultServer, o.pluginStateServer],
|
||||
[PluginConfig.State.CurrentServer, o.pluginStateServer],
|
||||
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
|
||||
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
|
||||
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
|
||||
[ShowButtons, showButtons]
|
||||
]
|
||||
};
|
||||
|
||||
const element = typeof elementOrId === 'string'
|
||||
? document.getElementById(elementOrId)
|
||||
: elementOrId;
|
||||
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
|
||||
this.plugin = createPlugin(element, spec);
|
||||
|
||||
(this.plugin.customState as any) = {
|
||||
colorPalette: {
|
||||
name: 'colors',
|
||||
params: { list: { colors } }
|
||||
}
|
||||
};
|
||||
|
||||
this.plugin.behaviors.canvas3d.initialized.subscribe(v => {
|
||||
if (v) {
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
|
||||
renderer: {
|
||||
...this.plugin.canvas3d!.props.renderer,
|
||||
backgroundColor: ColorNames.white,
|
||||
},
|
||||
camera: {
|
||||
...this.plugin.canvas3d!.props.camera,
|
||||
helper: { axes: { name: 'off', params: {} } }
|
||||
}
|
||||
} });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async loadStructuresFromUrlsAndMerge(sources: { url: string, format: BuiltInTrajectoryFormat, isBinary?: boolean }[]) {
|
||||
const structures: { ref: string }[] = [];
|
||||
for (const { url, format, isBinary } of sources) {
|
||||
const data = await this.plugin.builders.data.download({ url, isBinary });
|
||||
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
|
||||
const model = await this.plugin.builders.structure.createModel(trajectory);
|
||||
const modelProperties = await this.plugin.builders.structure.insertModelProperties(model);
|
||||
const structure = await this.plugin.builders.structure.createStructure(modelProperties || model);
|
||||
const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
|
||||
|
||||
structures.push({ ref: structureProperties?.ref || structure.ref });
|
||||
}
|
||||
|
||||
// remove current structuresfrom hierarchy as they will be merged
|
||||
// TODO only works with using loadStructuresFromUrlsAndMerge once
|
||||
// need some more API metho to work with the hierarchy
|
||||
this.plugin.managers.structure.hierarchy.updateCurrent(this.plugin.managers.structure.hierarchy.current.structures, 'remove');
|
||||
|
||||
const dependsOn = structures.map(({ ref }) => ref);
|
||||
const data = this.plugin.state.data.build().toRoot().apply(MergeStructures, { structures }, { dependsOn });
|
||||
const structure = await data.commit();
|
||||
const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
|
||||
this.plugin.behaviors.canvas3d.initialized.subscribe(async v => {
|
||||
await this.plugin.builders.structure.representation.applyPreset(structureProperties || structure, StructurePreset);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
type MergeStructures = typeof MergeStructures
|
||||
const MergeStructures = PluginStateTransform.BuiltIn({
|
||||
name: 'merge-structures',
|
||||
display: { name: 'Merge Structures', description: 'Merge Structure' },
|
||||
from: PSO.Root,
|
||||
to: PSO.Molecule.Structure,
|
||||
params: {
|
||||
structures: PD.ObjectList({
|
||||
ref: PD.Text('')
|
||||
}, ({ ref }) => ref, { isHidden: true })
|
||||
}
|
||||
})({
|
||||
apply({ params, dependencies }) {
|
||||
return Task.create('Merge Structures', async ctx => {
|
||||
if (params.structures.length === 0) return StateObject.Null;
|
||||
|
||||
const first = dependencies![params.structures[0].ref].data as Structure;
|
||||
const builder = Structure.Builder({ masterModel: first.models[0] });
|
||||
for (const { ref } of params.structures) {
|
||||
const s = dependencies![ref].data as Structure;
|
||||
for (const unit of s.units) {
|
||||
// TODO invariantId
|
||||
builder.addUnit(unit.kind, unit.model, unit.conformation.operator, unit.elements, unit.traits);
|
||||
}
|
||||
}
|
||||
|
||||
const structure = builder.getStructure();
|
||||
return new PSO.Molecule.Structure(structure, { label: 'Merged Structure' });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
(window as any).DockingViewer = Viewer;
|
||||
273
src/apps/docking-viewer/viewport.tsx
Normal file
273
src/apps/docking-viewer/viewport.tsx
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { InteractionsRepresentationProvider } from '../../mol-model-props/computed/representations/interactions';
|
||||
import { InteractionTypeColorThemeProvider } from '../../mol-model-props/computed/themes/interaction-type';
|
||||
import { presetStaticComponent, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { StructureSelectionQueries, StructureSelectionQuery } from '../../mol-plugin-state/helpers/structure-selection-query';
|
||||
import { StructureRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
|
||||
import { PluginUIComponent } from '../../mol-plugin-ui/base';
|
||||
import { LociLabels } from '../../mol-plugin-ui/controls';
|
||||
import { Button } from '../../mol-plugin-ui/controls/common';
|
||||
import { BackgroundTaskProgress } from '../../mol-plugin-ui/task';
|
||||
import { Toasts } from '../../mol-plugin-ui/toast';
|
||||
import { Viewport, ViewportControls } from '../../mol-plugin-ui/viewport';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { StateObjectRef } from '../../mol-state';
|
||||
import { Color } from '../../mol-util/color';
|
||||
|
||||
function shinyStyle(plugin: PluginContext) {
|
||||
return PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
|
||||
renderer: {
|
||||
...plugin.canvas3d!.props.renderer,
|
||||
},
|
||||
postprocessing: {
|
||||
...plugin.canvas3d!.props.postprocessing,
|
||||
occlusion: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} }
|
||||
}
|
||||
} });
|
||||
}
|
||||
|
||||
function occlusionStyle(plugin: PluginContext) {
|
||||
return PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
|
||||
renderer: {
|
||||
...plugin.canvas3d!.props.renderer,
|
||||
},
|
||||
postprocessing: {
|
||||
...plugin.canvas3d!.props.postprocessing,
|
||||
occlusion: { name: 'on', params: {
|
||||
samples: 64,
|
||||
radius: 8,
|
||||
bias: 1.0,
|
||||
blurKernelSize: 13
|
||||
} },
|
||||
outline: { name: 'on', params: {
|
||||
scale: 1.0,
|
||||
threshold: 0.33
|
||||
} }
|
||||
}
|
||||
} });
|
||||
}
|
||||
|
||||
const ligandPlusSurroundings = StructureSelectionQuery('Surrounding Residues (5 \u212B) of Ligand plus Ligand itself', MS.struct.modifier.union([
|
||||
MS.struct.modifier.includeSurroundings({
|
||||
0: StructureSelectionQueries.ligand.expression,
|
||||
radius: 5,
|
||||
'as-whole-residues': true
|
||||
})
|
||||
]));
|
||||
|
||||
const ligandSurroundings = StructureSelectionQuery('Surrounding Residues (5 \u212B) of Ligand', MS.struct.modifier.union([
|
||||
MS.struct.modifier.exceptBy({
|
||||
0: ligandPlusSurroundings.expression,
|
||||
by: StructureSelectionQueries.ligand.expression
|
||||
})
|
||||
]));
|
||||
|
||||
const PresetParams = {
|
||||
...StructureRepresentationPresetProvider.CommonParams,
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const StructurePreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-structure',
|
||||
display: { name: 'Structure' },
|
||||
params: () => PresetParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
if (!structureCell) return {};
|
||||
|
||||
const components = {
|
||||
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
|
||||
polymer: await presetStaticComponent(plugin, structureCell, 'polymer'),
|
||||
};
|
||||
|
||||
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
|
||||
const representations = {
|
||||
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.35 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
|
||||
polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams, roughness: 0.2 }, color: 'chain-id', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }),
|
||||
};
|
||||
|
||||
await update.commit({ revertOnError: true });
|
||||
await shinyStyle(plugin);
|
||||
plugin.managers.interactivity.setProps({ granularity: 'residue' });
|
||||
|
||||
return { components, representations };
|
||||
}
|
||||
});
|
||||
|
||||
export const IllustrativePreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-illustrative',
|
||||
display: { name: 'Illustrative' },
|
||||
params: () => PresetParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
if (!structureCell) return {};
|
||||
|
||||
const components = {
|
||||
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
|
||||
polymer: await presetStaticComponent(plugin, structureCell, 'polymer'),
|
||||
};
|
||||
|
||||
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
|
||||
const representations = {
|
||||
ligand: builder.buildRepresentation(update, components.ligand, { type: 'spacefill', typeParams: { ...typeParams, ignoreLight: true }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
|
||||
polymer: builder.buildRepresentation(update, components.polymer, { type: 'spacefill', typeParams: { ...typeParams, ignoreLight: true }, color: 'illustrative', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }),
|
||||
};
|
||||
|
||||
await update.commit({ revertOnError: true });
|
||||
await occlusionStyle(plugin);
|
||||
plugin.managers.interactivity.setProps({ granularity: 'residue' });
|
||||
|
||||
return { components, representations };
|
||||
}
|
||||
});
|
||||
|
||||
const SurfacePreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-surface',
|
||||
display: { name: 'Surface' },
|
||||
params: () => PresetParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
const components = {
|
||||
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
|
||||
polymer: await presetStaticComponent(plugin, structureCell, 'polymer'),
|
||||
};
|
||||
|
||||
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
|
||||
const representations = {
|
||||
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
|
||||
polymer: builder.buildRepresentation(update, components.polymer, { type: 'molecular-surface', typeParams: { ...typeParams, roughness: 0.2, quality: 'custom', resolution: 0.5, doubleSided: true }, color: 'partial-charge' }, { tag: 'polymer' }),
|
||||
};
|
||||
|
||||
await update.commit({ revertOnError: true });
|
||||
await shinyStyle(plugin);
|
||||
plugin.managers.interactivity.setProps({ granularity: 'residue' });
|
||||
|
||||
return { components, representations };
|
||||
}
|
||||
});
|
||||
|
||||
const PocketPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-pocket',
|
||||
display: { name: 'Pocket' },
|
||||
params: () => PresetParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
const components = {
|
||||
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
|
||||
surroundings: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandSurroundings, `surroundings`),
|
||||
};
|
||||
|
||||
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
|
||||
const representations = {
|
||||
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
|
||||
surroundings: builder.buildRepresentation(update, components.surroundings, { type: 'molecular-surface', typeParams: { ...typeParams, roughness: 0.2, includeParent: true, quality: 'custom', resolution: 0.2, doubleSided: true }, color: 'partial-charge' }, { tag: 'surroundings' }),
|
||||
};
|
||||
|
||||
await update.commit({ revertOnError: true });
|
||||
await shinyStyle(plugin);
|
||||
plugin.managers.interactivity.setProps({ granularity: 'element' });
|
||||
|
||||
return { components, representations };
|
||||
}
|
||||
});
|
||||
|
||||
const InteractionsPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-interactions',
|
||||
display: { name: 'Interactions' },
|
||||
params: () => PresetParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
const components = {
|
||||
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
|
||||
surroundings: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandSurroundings, `surroundings`),
|
||||
interactions: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandPlusSurroundings, `interactions`)
|
||||
};
|
||||
|
||||
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
|
||||
const representations = {
|
||||
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.3 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
|
||||
ballAndStick: builder.buildRepresentation(update, components.surroundings, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.1, sizeAspectRatio: 1 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ball-and-stick' }),
|
||||
interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams, roughness: 0.2 }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }),
|
||||
label: builder.buildRepresentation(update, components.surroundings, { type: 'label', typeParams: { ...typeParams, roughness: 0.2, background: false, borderWidth: 0.1 }, color: 'uniform', colorParams: { value: Color(0x000000) } }, { tag: 'label' }),
|
||||
};
|
||||
|
||||
await update.commit({ revertOnError: true });
|
||||
await shinyStyle(plugin);
|
||||
plugin.managers.interactivity.setProps({ granularity: 'element' });
|
||||
|
||||
return { components, representations };
|
||||
}
|
||||
});
|
||||
|
||||
export const ShowButtons = PluginConfig.item('showButtons', true);
|
||||
|
||||
export class ViewportComponent extends PluginUIComponent {
|
||||
async _set(structures: readonly StructureRef[], preset: StructureRepresentationPresetProvider) {
|
||||
await this.plugin.managers.structure.component.clear(structures);
|
||||
await this.plugin.managers.structure.component.applyPreset(structures, preset);
|
||||
}
|
||||
|
||||
set = async (preset: StructureRepresentationPresetProvider) => {
|
||||
await this._set(this.plugin.managers.structure.hierarchy.selection.structures, preset);
|
||||
}
|
||||
|
||||
structurePreset = () => this.set(StructurePreset);
|
||||
illustrativePreset = () => this.set(IllustrativePreset);
|
||||
surfacePreset = () => this.set(SurfacePreset);
|
||||
pocketPreset = () => this.set(PocketPreset);
|
||||
interactionsPreset = () => this.set(InteractionsPreset);
|
||||
|
||||
get showButtons() {
|
||||
return this.plugin.config.get(ShowButtons);
|
||||
}
|
||||
|
||||
render() {
|
||||
const VPControls = this.plugin.spec.components?.viewport?.controls || ViewportControls;
|
||||
|
||||
return <>
|
||||
<Viewport />
|
||||
{this.showButtons && <div className='msp-viewport-top-left-controls'>
|
||||
<div style={{ marginBottom: '4px' }}>
|
||||
<Button onClick={this.structurePreset} >Structure</Button>
|
||||
</div>
|
||||
<div style={{ marginBottom: '4px' }}>
|
||||
<Button onClick={this.illustrativePreset}>Illustrative</Button>
|
||||
</div>
|
||||
<div style={{ marginBottom: '4px' }}>
|
||||
<Button onClick={this.surfacePreset}>Surface</Button>
|
||||
</div>
|
||||
{/* <div style={{ marginBottom: '4px' }}>
|
||||
<Button onClick={this.pocketPreset}>Pocket</Button>
|
||||
</div> */}
|
||||
<div style={{ marginBottom: '4px' }}>
|
||||
<Button onClick={this.interactionsPreset}>Interactions</Button>
|
||||
</div>
|
||||
</div>}
|
||||
<VPControls />
|
||||
<BackgroundTaskProgress />
|
||||
<div className='msp-highlight-toast-wrapper'>
|
||||
<LociLabels />
|
||||
<Toasts />
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<title>Mol* ModelServer Query Builder</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="./index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,134 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as React from 'react'
|
||||
import * as ReactDOM from 'react-dom'
|
||||
import * as Rx from 'rxjs'
|
||||
|
||||
import { QueryDefinition, QueryList } from '../../servers/model/server/api'
|
||||
|
||||
import './index.html'
|
||||
|
||||
interface State {
|
||||
query: Rx.BehaviorSubject<QueryDefinition>,
|
||||
id: Rx.BehaviorSubject<string>,
|
||||
params: Rx.BehaviorSubject<any>,
|
||||
isBinary: Rx.BehaviorSubject<boolean>,
|
||||
models: Rx.BehaviorSubject<number[]>,
|
||||
url: Rx.Subject<string>
|
||||
}
|
||||
|
||||
class Root extends React.Component<{ state: State }, { }> {
|
||||
render() {
|
||||
return <div>
|
||||
<div>
|
||||
Query: <QuerySelect state={this.props.state} />
|
||||
</div>
|
||||
<div>
|
||||
ID: <input type='text' onChange={t => this.props.state.id.next(t.currentTarget.value)} />
|
||||
</div>
|
||||
<div>
|
||||
Params:<br/>
|
||||
<QueryParams state={this.props.state} />
|
||||
</div>
|
||||
<div>
|
||||
Model numbers (empty for all): <ModelNums state={this.props.state} />
|
||||
</div>
|
||||
<div>
|
||||
<input type='checkbox' onChange={t => this.props.state.isBinary.next(!!t.currentTarget.checked)} /> Binary
|
||||
</div>
|
||||
<div>
|
||||
Query string:
|
||||
<QueryUrl state={this.props.state} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
class QuerySelect extends React.Component<{ state: State }> {
|
||||
render() {
|
||||
return <select onChange={s => this.props.state.query.next(QueryList[+s.currentTarget.value].definition)}>
|
||||
{ QueryList.map((q, i) => <option value={i} key={i} selected={i === 1}>{q.definition.niceName}</option>) }
|
||||
</select>
|
||||
}
|
||||
}
|
||||
|
||||
class QueryParams extends React.Component<{ state: State }, { prms: string }> {
|
||||
state = { prms: '' };
|
||||
|
||||
parseParams(str: string) {
|
||||
this.setState({ prms: str });
|
||||
try {
|
||||
const params = JSON.parse(str);
|
||||
this.props.state.params.next(params);
|
||||
} catch {
|
||||
this.props.state.params.next({});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.state.query.subscribe(q => this.setState({ prms: formatParams(q) }))
|
||||
}
|
||||
|
||||
render() {
|
||||
return <textarea style={{height: '300px'}} value={this.state.prms} cols={80} onChange={t => this.parseParams(t.currentTarget.value)} />;
|
||||
}
|
||||
}
|
||||
|
||||
class QueryUrl extends React.Component<{ state: State }, { queryString: string }> {
|
||||
state = { queryString: '' };
|
||||
|
||||
componentDidMount() {
|
||||
this.props.state.url.subscribe(url => this.setState({ queryString: url }))
|
||||
}
|
||||
|
||||
render() {
|
||||
return <input type='text' value={this.state.queryString} style={{ width: '800px' }} />
|
||||
}
|
||||
}
|
||||
|
||||
class ModelNums extends React.Component<{ state: State }> {
|
||||
render() {
|
||||
return <input type='text' defaultValue='1' style={{ width: '300px' }} onChange={t =>
|
||||
this.props.state.models.next(t.currentTarget.value.split(',')
|
||||
.map(v => v.trim())
|
||||
.filter(v => !!v)
|
||||
.map(v => +v)
|
||||
)} />
|
||||
}
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
query: new Rx.BehaviorSubject(QueryList[1].definition),
|
||||
id: new Rx.BehaviorSubject('1cbs'),
|
||||
params: new Rx.BehaviorSubject({ }),
|
||||
isBinary: new Rx.BehaviorSubject<boolean>(false),
|
||||
models: new Rx.BehaviorSubject<number[]>([]),
|
||||
url: new Rx.Subject()
|
||||
}
|
||||
|
||||
function formatParams(def: QueryDefinition) {
|
||||
const prms = Object.create(null);
|
||||
for (const p of def.params) {
|
||||
prms[p.name] = p.exampleValues ? p.exampleValues[0] : void 0;
|
||||
}
|
||||
return JSON.stringify(prms, void 0, 2);
|
||||
}
|
||||
|
||||
function formatUrl() {
|
||||
const json = JSON.stringify({
|
||||
name: state.query.value.name,
|
||||
id: state.id.value,
|
||||
modelNums: state.models.value.length ? state.models.value : void 0,
|
||||
binary: state.isBinary.value,
|
||||
params: state.params.value
|
||||
});
|
||||
state.url.next(encodeURIComponent(json));
|
||||
}
|
||||
|
||||
Rx.merge(state.query, state.id, state.params, state.isBinary, state.models).subscribe(s => formatUrl());
|
||||
|
||||
ReactDOM.render(<Root state={state} />, document.getElementById('app'));
|
||||
44
src/apps/viewer/embedded.html
Normal file
44
src/apps/viewer/embedded.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<title>Embedded Mol* Viewer</title>
|
||||
<style>
|
||||
#app {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="./molstar.js"></script>
|
||||
<script type="text/javascript">
|
||||
var viewer = new molstar.Viewer('app', {
|
||||
layoutIsExpanded: true,
|
||||
layoutShowControls: false,
|
||||
layoutShowRemoteState: false,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: false,
|
||||
layoutShowLeftPanel: true,
|
||||
|
||||
viewportShowExpand: true,
|
||||
viewportShowSelectionMode: false,
|
||||
viewportShowAnimation: false,
|
||||
|
||||
pdbProvider: 'rcsb',
|
||||
emdbProvider: 'rcsb',
|
||||
});
|
||||
viewer.loadPdb('7bv2');
|
||||
viewer.loadEmdb('EMD-30210', { detail: 6 });
|
||||
|
||||
// viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { StateTree, StateBuilder, StateAction, State } from '../../../mol-state';
|
||||
import { StateTransforms } from '../../../mol-plugin/state/transforms';
|
||||
import { createModelTree, complexRepresentation } from '../../../mol-plugin/state/actions/structure';
|
||||
import { PluginContext } from '../../../mol-plugin/context';
|
||||
import { PluginStateObject } from '../../../mol-plugin/state/objects';
|
||||
import { ParamDefinition } from '../../../mol-util/param-definition';
|
||||
import { PluginCommands } from '../../../mol-plugin/command';
|
||||
import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { PluginStateSnapshotManager } from '../../../mol-plugin/state/snapshots';
|
||||
import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
|
||||
import { Text } from '../../../mol-geo/geometry/text/text';
|
||||
import { UUID } from '../../../mol-util';
|
||||
import { ColorNames } from '../../../mol-util/color/tables';
|
||||
import { Camera } from '../../../mol-canvas3d/camera';
|
||||
import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/transforms/representation';
|
||||
|
||||
export const CreateJoleculeState = StateAction.build({
|
||||
display: { name: 'Jolecule State Import' },
|
||||
params: { id: ParamDefinition.Text('1mbo') },
|
||||
from: PluginStateObject.Root
|
||||
})(async ({ ref, state, params }, plugin: PluginContext) => {
|
||||
try {
|
||||
const id = params.id.trim().toLowerCase();
|
||||
const data = await plugin.runTask(plugin.fetch({ url: `https://jolecule.appspot.com/pdb/${id}.views.json`, type: 'json' })) as JoleculeSnapshot[];
|
||||
|
||||
data.sort((a, b) => a.order - b.order);
|
||||
|
||||
await PluginCommands.State.RemoveObject.dispatch(plugin, { state, ref });
|
||||
plugin.state.snapshots.clear();
|
||||
|
||||
const template = createTemplate(plugin, state, id);
|
||||
const snapshots = data.map((e, idx) => buildSnapshot(plugin, template, { e, idx, len: data.length }));
|
||||
for (const s of snapshots) {
|
||||
plugin.state.snapshots.add(s);
|
||||
}
|
||||
|
||||
PluginCommands.State.Snapshots.Apply.dispatch(plugin, { id: snapshots[0].snapshot.id });
|
||||
} catch (e) {
|
||||
plugin.log.error(`Jolecule Failed: ${e}`);
|
||||
}
|
||||
});
|
||||
|
||||
interface JoleculeSnapshot {
|
||||
order: number,
|
||||
distances: { i_atom1: number, i_atom2: number }[],
|
||||
labels: { i_atom: number, text: string }[],
|
||||
camera: { up: Vec3, pos: Vec3, in: Vec3, slab: { z_front: number, z_back: number, zoom: number } },
|
||||
selected: number[],
|
||||
text: string
|
||||
}
|
||||
|
||||
function createTemplate(plugin: PluginContext, state: State, id: string) {
|
||||
const b = new StateBuilder.Root(state.tree);
|
||||
const data = b.toRoot().apply(StateTransforms.Data.Download, { url: `https://www.ebi.ac.uk/pdbe/static/entry/${id}_updated.cif` }, { state: { isGhost: true }});
|
||||
const model = createModelTree(data, 'cif');
|
||||
const structure = model.apply(StateTransforms.Model.StructureFromModel, {});
|
||||
complexRepresentation(plugin, structure, { hideWater: true });
|
||||
return { tree: b.getTree(), structure: structure.ref };
|
||||
}
|
||||
|
||||
const labelOptions: ParamDefinition.Values<Text.Params> = {
|
||||
...ParamDefinition.getDefaultValues(Text.Params),
|
||||
tether: true,
|
||||
sizeFactor: 1.3,
|
||||
attachment: 'bottom-right',
|
||||
offsetZ: 10,
|
||||
background: true,
|
||||
backgroundMargin: 0.2,
|
||||
backgroundColor: ColorNames.skyblue,
|
||||
backgroundOpacity: 0.9
|
||||
}
|
||||
|
||||
// const distanceLabelOptions = {
|
||||
// ...ParamDefinition.getDefaultValues(Text.Params),
|
||||
// sizeFactor: 1,
|
||||
// offsetX: 0,
|
||||
// offsetY: 0,
|
||||
// offsetZ: 10,
|
||||
// background: true,
|
||||
// backgroundMargin: 0.2,
|
||||
// backgroundColor: ColorNames.snow,
|
||||
// backgroundOpacity: 0.9
|
||||
// }
|
||||
|
||||
function buildSnapshot(plugin: PluginContext, template: { tree: StateTree, structure: string }, params: { e: JoleculeSnapshot, idx: number, len: number }): PluginStateSnapshotManager.Entry {
|
||||
const b = new StateBuilder.Root(template.tree);
|
||||
|
||||
let i = 0;
|
||||
for (const l of params.e.labels) {
|
||||
const query = createQuery([l.i_atom]);
|
||||
const group = b.to(template.structure)
|
||||
.group(StateTransforms.Misc.CreateGroup, { label: `Label ${++i}` });
|
||||
|
||||
group
|
||||
.apply(StateTransforms.Model.StructureSelection, { query, label: 'Atom' })
|
||||
.apply(StateTransforms.Representation.StructureLabels3D, {
|
||||
target: { name: 'static-text', params: { value: l.text || '' } },
|
||||
options: labelOptions
|
||||
});
|
||||
|
||||
group
|
||||
.apply(StateTransforms.Model.StructureSelection, { query: MS.struct.modifier.wholeResidues([query]), label: 'Residue' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick', { }));
|
||||
}
|
||||
if (params.e.selected && params.e.selected.length > 0) {
|
||||
b.to(template.structure)
|
||||
.apply(StateTransforms.Model.StructureSelection, { query: createQuery(params.e.selected), label: `Selected` })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick'));
|
||||
}
|
||||
// TODO
|
||||
// for (const l of params.e.distances) {
|
||||
// b.to('structure')
|
||||
// .apply(StateTransforms.Model.StructureSelection, { query: createQuery([l.i_atom1, l.i_atom2]), label: `Distance ${++i}` })
|
||||
// .apply(StateTransforms.Representation.StructureLabels3D, {
|
||||
// target: { name: 'static-text', params: { value: l. || '' } },
|
||||
// options: labelOptions
|
||||
// });
|
||||
// }
|
||||
return PluginStateSnapshotManager.Entry({
|
||||
id: UUID.create22(),
|
||||
data: { tree: StateTree.toJSON(b.getTree()) },
|
||||
camera: {
|
||||
current: getCameraSnapshot(params.e.camera),
|
||||
transitionStyle: 'animate',
|
||||
transitionDurationInMs: 350
|
||||
}
|
||||
}, {
|
||||
name: params.e.text
|
||||
});
|
||||
}
|
||||
|
||||
function getCameraSnapshot(e: JoleculeSnapshot['camera']): Camera.Snapshot {
|
||||
const direction = Vec3.sub(Vec3.zero(), e.pos, e.in);
|
||||
Vec3.normalize(direction, direction);
|
||||
const up = Vec3.sub(Vec3.zero(), e.pos, e.up);
|
||||
Vec3.normalize(up, up);
|
||||
|
||||
const s: Camera.Snapshot = {
|
||||
mode: 'perspective',
|
||||
position: Vec3.scaleAndAdd(Vec3.zero(), e.pos, direction, e.slab.zoom),
|
||||
target: e.pos,
|
||||
direction,
|
||||
up,
|
||||
near: e.slab.zoom + e.slab.z_front,
|
||||
far: e.slab.zoom + e.slab.z_back,
|
||||
fogNear: e.slab.zoom + e.slab.z_front,
|
||||
fogFar: e.slab.zoom + e.slab.z_back,
|
||||
fov: Math.PI / 4,
|
||||
zoom: 1
|
||||
};
|
||||
return s;
|
||||
}
|
||||
|
||||
function createQuery(atomIndices: number[]) {
|
||||
if (atomIndices.length === 0) return MS.struct.generator.empty();
|
||||
|
||||
return MS.struct.generator.atomGroups({
|
||||
'atom-test': atomIndices.length === 1
|
||||
? MS.core.rel.eq([MS.struct.atomProperty.core.sourceIndex(), atomIndices[0]])
|
||||
: MS.core.set.has([MS.set.apply(null, atomIndices), MS.struct.atomProperty.core.sourceIndex()]),
|
||||
'group-by': 0
|
||||
});
|
||||
}
|
||||
BIN
src/apps/viewer/favicon.ico
Executable file
BIN
src/apps/viewer/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<title>Mol* Viewer</title>
|
||||
<style>
|
||||
* {
|
||||
@@ -33,10 +34,62 @@
|
||||
height: 600px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="app.css" />
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="./index.js"></script>
|
||||
<script type="text/javascript" src="./molstar.js"></script>
|
||||
<script type="text/javascript">
|
||||
function getParam(name, regex) {
|
||||
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
|
||||
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
|
||||
}
|
||||
|
||||
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
|
||||
if (debugMode) molstar.setDebugMode(debugMode, debugMode);
|
||||
|
||||
var hideControls = getParam('hide-controls', '[^&]+').trim() === '1';
|
||||
var collapseLeftPanel = getParam('collapse-left-panel', '[^&]+').trim() === '1';
|
||||
var pdbProvider = getParam('pdb-provider', '[^&]+').trim().toLowerCase();
|
||||
var emdbProvider = getParam('emdb-provider', '[^&]+').trim().toLowerCase();
|
||||
var mapProvider = getParam('map-provider', '[^&]+').trim().toLowerCase();
|
||||
var pixelScale = getParam('pixel-scale', '[^&]+').trim();
|
||||
var pickScale = getParam('pick-scale', '[^&]+').trim();
|
||||
var pickPadding = getParam('pick-padding', '[^&]+').trim();
|
||||
var viewer = new molstar.Viewer('app', {
|
||||
layoutShowControls: !hideControls,
|
||||
viewportShowExpand: false,
|
||||
collapseLeftPanel: collapseLeftPanel,
|
||||
pdbProvider: pdbProvider || 'pdbe',
|
||||
emdbProvider: emdbProvider || 'pdbe',
|
||||
volumeStreamingServer: (mapProvider || 'pdbe') === 'rcsb'
|
||||
? 'https://maps.rcsb.org'
|
||||
: 'https://www.ebi.ac.uk/pdbe/densities',
|
||||
pixelScale: parseFloat(pixelScale) || 1,
|
||||
pickScale: parseFloat(pickScale) || 0.25,
|
||||
pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
|
||||
});
|
||||
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
|
||||
|
||||
var snapshotUrl = getParam('snapshot-url', '[^&]+').trim();
|
||||
var snapshotUrlType = getParam('snapshot-url-type', '[^&]+').toLowerCase().trim() || 'molj';
|
||||
if (snapshotUrl && snapshotUrlType) viewer.loadSnapshotFromUrl(snapshotUrl, snapshotUrlType);
|
||||
|
||||
var structureUrl = getParam('structure-url', '[^&]+').trim();
|
||||
var structureUrlFormat = getParam('structure-url-format', '[a-z]+').toLowerCase().trim();
|
||||
var structureUrlIsBinary = getParam('structure-url-is-binary', '[^&]+').trim() === '1';
|
||||
if (structureUrl) viewer.loadStructureFromUrl(structureUrl, structureUrlFormat, structureUrlIsBinary);
|
||||
|
||||
var pdb = getParam('pdb', '[^&]+').trim();
|
||||
if (pdb) viewer.loadPdb(pdb);
|
||||
|
||||
var pdbDev = getParam('pdb-dev', '[^&]+').trim();
|
||||
if (pdbDev) viewer.loadPdbDev(pdbDev);
|
||||
|
||||
var emdb = getParam('emdb', '[^&]+').trim();
|
||||
if (emdb) viewer.loadEmdb(emdb);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,55 +1,412 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
|
||||
import './index.html'
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { PluginCommands } from '../../mol-plugin/command';
|
||||
import { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
|
||||
import { CellPack } from '../../extensions/cellpack';
|
||||
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
|
||||
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
|
||||
import { GeometryExport } from '../../extensions/geo-export';
|
||||
import { Mp4Export } from '../../extensions/mp4-export';
|
||||
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
|
||||
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
|
||||
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
|
||||
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
|
||||
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
|
||||
import { StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
|
||||
import { BuildInStructureFormat } from '../../mol-plugin-state/formats/structure';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
|
||||
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
|
||||
import { PluginSpec } from '../../mol-plugin/spec';
|
||||
import { CreateJoleculeState } from './extensions/jolecule';
|
||||
require('mol-plugin/skin/light.scss')
|
||||
import { PluginState } from '../../mol-plugin/state';
|
||||
import { StateObjectSelector } from '../../mol-state';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import '../../mol-util/polyfill';
|
||||
import { ObjectKeys } from '../../mol-util/type-helpers';
|
||||
import './embedded.html';
|
||||
import './favicon.ico';
|
||||
import './index.html';
|
||||
|
||||
function getParam(name: string, regex: string): string {
|
||||
let r = new RegExp(`${name}=(${regex})[&]?`, 'i');
|
||||
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
|
||||
}
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
|
||||
const hideControls = getParam('hide-controls', `[^&]+`) === '1';
|
||||
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
|
||||
export { setDebugMode, setProductionMode } from '../../mol-util/debug';
|
||||
|
||||
function init() {
|
||||
const spec: PluginSpec = {
|
||||
actions: [...DefaultPluginSpec.actions, PluginSpec.Action(CreateJoleculeState)],
|
||||
behaviors: [...DefaultPluginSpec.behaviors],
|
||||
animations: [...DefaultPluginSpec.animations || []],
|
||||
customParamEditors: DefaultPluginSpec.customParamEditors,
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: true,
|
||||
showControls: !hideControls
|
||||
const CustomFormats = [
|
||||
['g3d', G3dProvider] as const
|
||||
];
|
||||
|
||||
const Extensions = {
|
||||
'cellpack': PluginSpec.Behavior(CellPack),
|
||||
'dnatco-confal-pyramids': PluginSpec.Behavior(DnatcoConfalPyramids),
|
||||
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
|
||||
'rcsb-assembly-symmetry': PluginSpec.Behavior(RCSBAssemblySymmetry),
|
||||
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
|
||||
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
|
||||
'g3d': PluginSpec.Behavior(G3DFormat),
|
||||
'mp4-export': PluginSpec.Behavior(Mp4Export),
|
||||
'geo-export': PluginSpec.Behavior(GeometryExport)
|
||||
};
|
||||
|
||||
const DefaultViewerOptions = {
|
||||
customFormats: CustomFormats as [string, DataFormatProvider][],
|
||||
extensions: ObjectKeys(Extensions),
|
||||
layoutIsExpanded: true,
|
||||
layoutShowControls: true,
|
||||
layoutShowRemoteState: true,
|
||||
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: true,
|
||||
layoutShowLeftPanel: true,
|
||||
collapseLeftPanel: false,
|
||||
collapseRightPanel: false,
|
||||
disableAntialiasing: PluginConfig.General.DisableAntialiasing.defaultValue,
|
||||
pixelScale: PluginConfig.General.PixelScale.defaultValue,
|
||||
pickScale: PluginConfig.General.PickScale.defaultValue,
|
||||
pickPadding: PluginConfig.General.PickPadding.defaultValue,
|
||||
enableWboit: PluginConfig.General.EnableWboit.defaultValue,
|
||||
|
||||
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
|
||||
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
|
||||
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
|
||||
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
|
||||
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
|
||||
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
|
||||
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
|
||||
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
|
||||
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
|
||||
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
|
||||
};
|
||||
type ViewerOptions = typeof DefaultViewerOptions;
|
||||
|
||||
export class Viewer {
|
||||
plugin: PluginUIContext
|
||||
|
||||
constructor(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
|
||||
const o = { ...DefaultViewerOptions, ...options };
|
||||
const defaultSpec = DefaultPluginUISpec();
|
||||
|
||||
const spec: PluginUISpec = {
|
||||
actions: defaultSpec.actions,
|
||||
behaviors: [
|
||||
...defaultSpec.behaviors,
|
||||
...o.extensions.map(e => Extensions[e]),
|
||||
],
|
||||
animations: [...defaultSpec.animations || []],
|
||||
customParamEditors: defaultSpec.customParamEditors,
|
||||
customFormats: o?.customFormats,
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: o.layoutIsExpanded,
|
||||
showControls: o.layoutShowControls,
|
||||
controlsDisplay: o.layoutControlsDisplay,
|
||||
regionState: {
|
||||
bottom: 'full',
|
||||
left: o.collapseLeftPanel ? 'collapsed' : 'full',
|
||||
right: o.collapseRightPanel ? 'hidden' : 'full',
|
||||
top: 'full',
|
||||
}
|
||||
},
|
||||
},
|
||||
components: {
|
||||
...defaultSpec.components,
|
||||
controls: {
|
||||
...defaultSpec.components?.controls,
|
||||
top: o.layoutShowSequence ? undefined : 'none',
|
||||
bottom: o.layoutShowLog ? undefined : 'none',
|
||||
left: o.layoutShowLeftPanel ? undefined : 'none',
|
||||
},
|
||||
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
|
||||
},
|
||||
config: [
|
||||
[PluginConfig.General.DisableAntialiasing, o.disableAntialiasing],
|
||||
[PluginConfig.General.PixelScale, o.pixelScale],
|
||||
[PluginConfig.General.PickScale, o.pickScale],
|
||||
[PluginConfig.General.PickPadding, o.pickPadding],
|
||||
[PluginConfig.General.EnableWboit, o.enableWboit],
|
||||
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
|
||||
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
|
||||
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
|
||||
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
|
||||
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
|
||||
[PluginConfig.State.DefaultServer, o.pluginStateServer],
|
||||
[PluginConfig.State.CurrentServer, o.pluginStateServer],
|
||||
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
|
||||
[PluginConfig.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
|
||||
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
|
||||
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider]
|
||||
]
|
||||
};
|
||||
|
||||
const element = typeof elementOrId === 'string'
|
||||
? document.getElementById(elementOrId)
|
||||
: elementOrId;
|
||||
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
|
||||
this.plugin = createPlugin(element, spec);
|
||||
}
|
||||
|
||||
setRemoteSnapshot(id: string) {
|
||||
const url = `${this.plugin.config.get(PluginConfig.State.CurrentServer)}/get/${id}`;
|
||||
return PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
|
||||
}
|
||||
|
||||
loadSnapshotFromUrl(url: string, type: PluginState.SnapshotType) {
|
||||
return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
|
||||
}
|
||||
|
||||
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
|
||||
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
name: 'url',
|
||||
params: {
|
||||
url: Asset.Url(url),
|
||||
format: format as any,
|
||||
isBinary,
|
||||
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const plugin = createPlugin(document.getElementById('app')!, spec);
|
||||
trySetSnapshot(plugin);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async function trySetSnapshot(ctx: PluginContext) {
|
||||
try {
|
||||
const snapshotUrl = getParam('snapshot-url', `[^&]+`);
|
||||
const snapshotId = getParam('snapshot-id', `[^&]+`);
|
||||
if (!snapshotUrl && !snapshotId) return;
|
||||
// TODO parametrize the server
|
||||
const url = snapshotId
|
||||
? `https://webchem.ncbr.muni.cz/molstar-state/get/${snapshotId}`
|
||||
: snapshotUrl;
|
||||
await PluginCommands.State.Snapshots.Fetch.dispatch(ctx, { url })
|
||||
} catch (e) {
|
||||
ctx.log.error('Failed to load snapshot.');
|
||||
console.warn('Failed to load snapshot', e);
|
||||
async loadAllModelsOrAssemblyFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
|
||||
const plugin = this.plugin;
|
||||
|
||||
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
|
||||
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
|
||||
|
||||
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'all-models', { useDefaultIfSingleModel: true, representationPresetParams: options?.representationParams });
|
||||
}
|
||||
|
||||
async loadStructureFromData(data: string | number[], format: BuiltInTrajectoryFormat, options?: { dataLabel?: string }) {
|
||||
const _data = await this.plugin.builders.data.rawData({ data, label: options?.dataLabel });
|
||||
const trajectory = await this.plugin.builders.structure.parseTrajectory(_data, format);
|
||||
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default');
|
||||
}
|
||||
|
||||
loadPdb(pdb: string, options?: LoadStructureOptions) {
|
||||
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
const provider = this.plugin.config.get(PluginConfig.Download.DefaultPdbProvider)!;
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
name: 'pdb' as const,
|
||||
params: {
|
||||
provider: {
|
||||
id: pdb,
|
||||
server: {
|
||||
name: provider,
|
||||
params: PdbDownloadProvider[provider].defaultValue as any
|
||||
}
|
||||
},
|
||||
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
loadPdbDev(pdbDev: string) {
|
||||
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
name: 'pdb-dev' as const,
|
||||
params: {
|
||||
provider: {
|
||||
id: pdbDev,
|
||||
encoding: 'bcif',
|
||||
},
|
||||
options: params.source.params.options,
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
loadEmdb(emdb: string, options?: { detail?: number }) {
|
||||
const provider = this.plugin.config.get(PluginConfig.Download.DefaultEmdbProvider)!;
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
|
||||
source: {
|
||||
name: 'pdb-emd-ds' as const,
|
||||
params: {
|
||||
provider: {
|
||||
id: emdb,
|
||||
server: provider,
|
||||
},
|
||||
detail: options?.detail ?? 3,
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @example Load X-ray density from volume server
|
||||
viewer.loadVolumeFromUrl({
|
||||
url: 'https://www.ebi.ac.uk/pdbe/densities/x-ray/1tqn/cell?detail=3',
|
||||
format: 'dscif',
|
||||
isBinary: true
|
||||
}, [{
|
||||
type: 'relative',
|
||||
value: 1.5,
|
||||
color: 0x3362B2
|
||||
}, {
|
||||
type: 'relative',
|
||||
value: 3,
|
||||
color: 0x33BB33,
|
||||
volumeIndex: 1
|
||||
}, {
|
||||
type: 'relative',
|
||||
value: -3,
|
||||
color: 0xBB3333,
|
||||
volumeIndex: 1
|
||||
}], {
|
||||
entryId: ['2FO-FC', 'FO-FC'],
|
||||
isLazy: true
|
||||
});
|
||||
* *********************
|
||||
* @example Load EM density from volume server
|
||||
viewer.loadVolumeFromUrl({
|
||||
url: 'https://maps.rcsb.org/em/emd-30210/cell?detail=6',
|
||||
format: 'dscif',
|
||||
isBinary: true
|
||||
}, [{
|
||||
type: 'relative',
|
||||
value: 1,
|
||||
color: 0x3377aa
|
||||
}], {
|
||||
entryId: 'EMD-30210',
|
||||
isLazy: true
|
||||
});
|
||||
*/
|
||||
async loadVolumeFromUrl({ url, format, isBinary }: { url: string, format: BuildInVolumeFormat, isBinary: boolean }, isovalues: VolumeIsovalueInfo[], options?: { entryId?: string | string[], isLazy?: boolean }) {
|
||||
const plugin = this.plugin;
|
||||
|
||||
if (!plugin.dataFormats.get(format)) {
|
||||
throw new Error(`Unknown density format: ${format}`);
|
||||
}
|
||||
|
||||
if (options?.isLazy) {
|
||||
const update = this.plugin.build();
|
||||
update.toRoot().apply(StateTransforms.Data.LazyVolume, {
|
||||
url,
|
||||
format,
|
||||
entryId: options?.entryId,
|
||||
isBinary,
|
||||
isovalues: isovalues.map(v => ({ alpha: 1, volumeIndex: 0, ...v }))
|
||||
});
|
||||
return update.commit();
|
||||
}
|
||||
|
||||
return plugin.dataTransaction(async () => {
|
||||
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
|
||||
|
||||
const parsed = await plugin.dataFormats.get(format)!.parse(plugin, data, { entryId: options?.entryId });
|
||||
const firstVolume = (parsed.volume || parsed.volumes[0]) as StateObjectSelector<PluginStateObject.Volume.Data>;
|
||||
if (!firstVolume?.isOk) throw new Error('Failed to parse any volume.');
|
||||
|
||||
const repr = plugin.build();
|
||||
for (const iso of isovalues) {
|
||||
repr
|
||||
.to(parsed.volumes?.[iso.volumeIndex ?? 0] ?? parsed.volume)
|
||||
.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, firstVolume.data!, {
|
||||
type: 'isosurface',
|
||||
typeParams: { alpha: iso.alpha ?? 1, isoValue: iso.type === 'absolute' ? { kind: 'absolute', absoluteValue: iso.value } : { kind: 'relative', relativeValue: iso.value } },
|
||||
color: 'uniform',
|
||||
colorParams: { value: iso.color }
|
||||
}));
|
||||
}
|
||||
|
||||
await repr.commit();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @example
|
||||
* viewer.loadTrajectory({
|
||||
* model: { kind: 'model-url', url: 'villin.gro', format: 'gro' },
|
||||
* coordinates: { kind: 'coordinates-url', url: 'villin.xtc', format: 'xtc', isBinary: true },
|
||||
* preset: 'all-models' // or 'default'
|
||||
* });
|
||||
*/
|
||||
async loadTrajectory(params: LoadTrajectoryParams) {
|
||||
const plugin = this.plugin;
|
||||
|
||||
let model: StateObjectSelector, coords: StateObjectSelector;
|
||||
|
||||
if (params.model.kind === 'model-data' || params.model.kind === 'model-url') {
|
||||
const data = params.model.kind === 'model-data'
|
||||
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
|
||||
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
|
||||
|
||||
const trajectory = await plugin.builders.structure.parseTrajectory(data, params.model.format ?? 'mmcif');
|
||||
model = await plugin.builders.structure.createModel(trajectory);
|
||||
} else {
|
||||
const data = params.model.kind === 'topology-data'
|
||||
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
|
||||
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
|
||||
|
||||
const provider = plugin.dataFormats.get(params.model.format);
|
||||
model = await provider!.parse(plugin, data);
|
||||
}
|
||||
|
||||
{
|
||||
const data = params.coordinates.kind === 'coordinates-data'
|
||||
? await plugin.builders.data.rawData({ data: params.coordinates.data, label: params.coordinatesLabel })
|
||||
: await plugin.builders.data.download({ url: params.coordinates.url, isBinary: params.coordinates.isBinary, label: params.coordinatesLabel });
|
||||
|
||||
const provider = plugin.dataFormats.get(params.coordinates.format);
|
||||
coords = await provider!.parse(plugin, data);
|
||||
}
|
||||
|
||||
const trajectory = await plugin.build().toRoot()
|
||||
.apply(TrajectoryFromModelAndCoordinates, {
|
||||
modelRef: model.ref,
|
||||
coordinatesRef: coords.ref
|
||||
}, { dependsOn: [model.ref, coords.ref] })
|
||||
.commit();
|
||||
|
||||
const preset = await plugin.builders.structure.hierarchy.applyPreset(trajectory, params.preset ?? 'default');
|
||||
|
||||
return { model, coords, preset };
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
this.plugin.layout.events.updated.next(void 0);
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
export interface LoadStructureOptions {
|
||||
representationParams?: StructureRepresentationPresetProvider.CommonParams
|
||||
}
|
||||
|
||||
export interface VolumeIsovalueInfo {
|
||||
type: 'absolute' | 'relative',
|
||||
value: number,
|
||||
color: Color,
|
||||
alpha?: number,
|
||||
volumeIndex?: number
|
||||
}
|
||||
|
||||
export interface LoadTrajectoryParams {
|
||||
model: { kind: 'model-url', url: string, format?: BuiltInTrajectoryFormat /* mmcif */, isBinary?: boolean }
|
||||
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array, format?: BuiltInTrajectoryFormat /* mmcif */ }
|
||||
| { kind: 'topology-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
|
||||
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
|
||||
modelLabel?: string,
|
||||
coordinates: { kind: 'coordinates-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
|
||||
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
|
||||
coordinatesLabel?: string,
|
||||
preset?: keyof PresetTrajectoryHierarchy
|
||||
}
|
||||
73
src/cli/chem-comp-dict/create-ions.ts
Normal file
73
src/cli/chem-comp-dict/create-ions.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Josh McMenemy <josh.mcmenemy@gmail.com>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as path from 'path';
|
||||
import util from 'util';
|
||||
import fs from 'fs';
|
||||
require('util.promisify').shim();
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
|
||||
import { DatabaseCollection } from '../../mol-data/db';
|
||||
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
|
||||
import { ensureDataAvailable, readCCD } from './util';
|
||||
|
||||
function extractIonNames(ccd: DatabaseCollection<CCD_Schema>) {
|
||||
const ionNames: string[] = [];
|
||||
for (const k in ccd) {
|
||||
const { chem_comp } = ccd[k];
|
||||
if (chem_comp.name.value(0).toUpperCase().includes(' ION')) {
|
||||
ionNames.push(chem_comp.id.value(0));
|
||||
}
|
||||
}
|
||||
// these are extra ions that don't have ION in their name
|
||||
ionNames.push('NCO', 'OHX');
|
||||
return ionNames;
|
||||
}
|
||||
|
||||
function writeIonNamesFile(filePath: string, ionNames: string[]) {
|
||||
const output = `/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated ion names params file. Names extracted from CCD components.
|
||||
*
|
||||
* @author molstar/chem-comp-dict/create-table cli
|
||||
*/
|
||||
|
||||
export const IonNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});
|
||||
`;
|
||||
writeFile(filePath, output);
|
||||
}
|
||||
|
||||
async function run(out: string, forceDownload = false) {
|
||||
await ensureDataAvailable(forceDownload);
|
||||
const ccd = await readCCD();
|
||||
const ionNames = extractIonNames(ccd);
|
||||
if (!fs.existsSync(path.dirname(out))) {
|
||||
fs.mkdirSync(path.dirname(out));
|
||||
}
|
||||
writeIonNamesFile(out, ionNames);
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Extract and save IonNames from CCD.'
|
||||
});
|
||||
parser.add_argument('out', {
|
||||
help: 'Generated file output path.'
|
||||
});
|
||||
parser.add_argument('--forceDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of CCD and PVCD.'
|
||||
});
|
||||
interface Args {
|
||||
out: string,
|
||||
forceDownload?: boolean,
|
||||
}
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
run(args.out, args.forceDownload);
|
||||
294
src/cli/chem-comp-dict/create-table.ts
Normal file
294
src/cli/chem-comp-dict/create-table.ts
Normal file
@@ -0,0 +1,294 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as util from 'util';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
require('util.promisify').shim();
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
|
||||
import { Database, Table, DatabaseCollection } from '../../mol-data/db';
|
||||
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
|
||||
import { SetUtils } from '../../mol-util/set';
|
||||
import { DefaultMap } from '../../mol-util/map';
|
||||
import { mmCIF_chemCompBond_schema } from '../../mol-io/reader/cif/schema/mmcif-extras';
|
||||
import { ccd_chemCompAtom_schema } from '../../mol-io/reader/cif/schema/ccd-extras';
|
||||
import { ensureDataAvailable, getEncodedCif, readCCD, readPVCD } from './util';
|
||||
|
||||
type CCB = Table<CCD_Schema['chem_comp_bond']>
|
||||
type CCA = Table<CCD_Schema['chem_comp_atom']>
|
||||
|
||||
function ccbKey(compId: string, atomId1: string, atomId2: string) {
|
||||
return atomId1 < atomId2 ? `${compId}:${atomId1}-${atomId2}` : `${compId}:${atomId2}-${atomId1}`;
|
||||
}
|
||||
|
||||
function ccaKey(compId: string, atomId: string) {
|
||||
return `${compId}:${atomId}`;
|
||||
}
|
||||
|
||||
function addChemCompBondToSet(set: Set<string>, ccb: CCB) {
|
||||
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
|
||||
set.add(ccbKey(ccb.comp_id.value(i), ccb.atom_id_1.value(i), ccb.atom_id_2.value(i)));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
function addChemCompAtomToSet(set: Set<string>, cca: CCA) {
|
||||
for (let i = 0, il = cca._rowCount; i < il; ++i) {
|
||||
set.add(ccaKey(cca.comp_id.value(i), cca.atom_id.value(i)));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
function checkAddingBondsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
|
||||
const ccbSetByParent = DefaultMap<string, Set<string>>(() => new Set());
|
||||
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_bond } = pvcd[k];
|
||||
if (chem_comp_bond._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
|
||||
if (parentIds.length === 0) {
|
||||
const set = ccbSetByParent.getDefault(chem_comp.id.value(0));
|
||||
addChemCompBondToSet(set, chem_comp_bond);
|
||||
} else {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
const parentId = parentIds[i];
|
||||
const set = ccbSetByParent.getDefault(parentId);
|
||||
addChemCompBondToSet(set, chem_comp_bond);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_atom, chem_comp_bond } = pvcd[k];
|
||||
if (chem_comp_bond._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
|
||||
if (parentIds.length > 0) {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
const entryBonds = addChemCompBondToSet(new Set<string>(), chem_comp_bond);
|
||||
const entryAtoms = addChemCompAtomToSet(new Set<string>(), chem_comp_atom);
|
||||
const extraBonds = SetUtils.difference(ccbSetByParent.get(parentIds[i])!, entryBonds);
|
||||
extraBonds.forEach(bk => {
|
||||
const [a1, a2] = bk.split('|');
|
||||
if (entryAtoms.has(a1) && entryAtoms.has(a2)) {
|
||||
console.error(`Adding all PVCD bonds would wrongly add bond ${bk} for ${k}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkAddingAtomsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
|
||||
const ccaSetByParent = DefaultMap<string, Set<string>>(() => new Set());
|
||||
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_atom } = pvcd[k];
|
||||
if (chem_comp_atom._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
|
||||
if (parentIds.length === 0) {
|
||||
const set = ccaSetByParent.getDefault(chem_comp.id.value(0));
|
||||
addChemCompAtomToSet(set, chem_comp_atom);
|
||||
} else {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
const parentId = parentIds[i];
|
||||
const set = ccaSetByParent.getDefault(parentId);
|
||||
addChemCompAtomToSet(set, chem_comp_atom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createBonds(
|
||||
ccd: DatabaseCollection<CCD_Schema>,
|
||||
pvcd: DatabaseCollection<CCD_Schema>,
|
||||
atomsRequested: boolean
|
||||
) {
|
||||
const ccbSet = new Set<string>();
|
||||
|
||||
const comp_id: string[] = [];
|
||||
const atom_id_1: string[] = [];
|
||||
const atom_id_2: string[] = [];
|
||||
const value_order: typeof mmCIF_chemCompBond_schema['value_order']['T'][] = [];
|
||||
const pdbx_aromatic_flag: typeof mmCIF_chemCompBond_schema['pdbx_aromatic_flag']['T'][] = [];
|
||||
const pdbx_stereo_config: typeof mmCIF_chemCompBond_schema['pdbx_stereo_config']['T'][] = [];
|
||||
const molstar_protonation_variant: string[] = [];
|
||||
|
||||
function addBonds(compId: string, ccb: CCB, protonationVariant: boolean) {
|
||||
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
|
||||
const atomId1 = ccb.atom_id_1.value(i);
|
||||
const atomId2 = ccb.atom_id_2.value(i);
|
||||
const k = ccbKey(compId, atomId1, atomId2);
|
||||
if (!ccbSet.has(k)) {
|
||||
atom_id_1.push(atomId1);
|
||||
atom_id_2.push(atomId2);
|
||||
comp_id.push(compId);
|
||||
value_order.push(ccb.value_order.value(i));
|
||||
pdbx_aromatic_flag.push(ccb.pdbx_aromatic_flag.value(i));
|
||||
pdbx_stereo_config.push(ccb.pdbx_stereo_config.value(i));
|
||||
molstar_protonation_variant.push(protonationVariant ? 'Y' : 'N');
|
||||
ccbSet.add(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check adding bonds from PVCD
|
||||
checkAddingBondsFromPVCD(pvcd);
|
||||
|
||||
// add bonds from PVCD
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_bond } = pvcd[k];
|
||||
if (chem_comp_bond._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
|
||||
if (parentIds.length === 0) {
|
||||
addBonds(chem_comp.id.value(0), chem_comp_bond, false);
|
||||
} else {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
addBonds(parentIds[i], chem_comp_bond, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add bonds from CCD
|
||||
for (const k in ccd) {
|
||||
const { chem_comp, chem_comp_bond } = ccd[k];
|
||||
if (chem_comp_bond._rowCount) {
|
||||
addBonds(chem_comp.id.value(0), chem_comp_bond, false);
|
||||
}
|
||||
}
|
||||
|
||||
const bondTable = Table.ofArrays(mmCIF_chemCompBond_schema, {
|
||||
comp_id, atom_id_1, atom_id_2, value_order,
|
||||
pdbx_aromatic_flag, pdbx_stereo_config, molstar_protonation_variant
|
||||
});
|
||||
|
||||
const bondDatabase = Database.ofTables(
|
||||
CCB_TABLE_NAME,
|
||||
{ chem_comp_bond: mmCIF_chemCompBond_schema },
|
||||
{ chem_comp_bond: bondTable }
|
||||
);
|
||||
|
||||
return { bonds: bondDatabase, atoms: atomsRequested ? createAtoms(ccd, pvcd) : void 0 };
|
||||
}
|
||||
|
||||
function createAtoms(ccd: DatabaseCollection<CCD_Schema>, pvcd: DatabaseCollection<CCD_Schema>) {
|
||||
const ccaSet = new Set<string>();
|
||||
|
||||
const comp_id: string[] = [];
|
||||
const atom_id: string[] = [];
|
||||
const charge: number[] = [];
|
||||
const pdbx_stereo_config: typeof CCD_Schema.chem_comp_atom['pdbx_stereo_config']['T'][] = [];
|
||||
|
||||
function addAtoms(compId: string, cca: CCA) {
|
||||
for (let i = 0, il = cca._rowCount; i < il; ++i) {
|
||||
const atomId = cca.atom_id.value(i);
|
||||
const k = ccaKey(compId, atomId);
|
||||
if (!ccaSet.has(k)) {
|
||||
atom_id.push(atomId);
|
||||
comp_id.push(compId);
|
||||
charge.push(cca.charge.value(i));
|
||||
pdbx_stereo_config.push(cca.pdbx_stereo_config.value(i));
|
||||
ccaSet.add(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check adding atoms from PVCD
|
||||
checkAddingAtomsFromPVCD(pvcd);
|
||||
|
||||
// add atoms from PVCD
|
||||
for (const k in pvcd) {
|
||||
const { chem_comp, chem_comp_atom } = pvcd[k];
|
||||
if (chem_comp_atom._rowCount) {
|
||||
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
|
||||
if (parentIds.length === 0) {
|
||||
addAtoms(chem_comp.id.value(0), chem_comp_atom);
|
||||
} else {
|
||||
for (let i = 0, il = parentIds.length; i < il; ++i) {
|
||||
addAtoms(parentIds[i], chem_comp_atom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add atoms from CCD
|
||||
for (const k in ccd) {
|
||||
const { chem_comp, chem_comp_atom } = ccd[k];
|
||||
if (chem_comp_atom._rowCount) {
|
||||
addAtoms(chem_comp.id.value(0), chem_comp_atom);
|
||||
}
|
||||
}
|
||||
|
||||
const atomTable = Table.ofArrays(ccd_chemCompAtom_schema, {
|
||||
comp_id, atom_id, charge, pdbx_stereo_config
|
||||
});
|
||||
|
||||
return Database.ofTables(
|
||||
CCA_TABLE_NAME,
|
||||
{ chem_comp_atom: ccd_chemCompAtom_schema },
|
||||
{ chem_comp_atom: atomTable }
|
||||
);
|
||||
}
|
||||
|
||||
async function run(out: string, binary = false, forceDownload = false, ccaOut?: string) {
|
||||
await ensureDataAvailable(forceDownload);
|
||||
const ccd = await readCCD();
|
||||
const pvcd = await readPVCD();
|
||||
|
||||
const { bonds, atoms } = await createBonds(ccd, pvcd, !!ccaOut);
|
||||
|
||||
const ccbCif = getEncodedCif(CCB_TABLE_NAME, bonds, binary);
|
||||
if (!fs.existsSync(path.dirname(out))) {
|
||||
fs.mkdirSync(path.dirname(out));
|
||||
}
|
||||
writeFile(out, ccbCif);
|
||||
|
||||
if (!!ccaOut) {
|
||||
const ccaCif = getEncodedCif(CCA_TABLE_NAME, atoms, binary);
|
||||
if (!fs.existsSync(path.dirname(ccaOut))) {
|
||||
fs.mkdirSync(path.dirname(ccaOut));
|
||||
}
|
||||
writeFile(ccaOut, ccaCif);
|
||||
}
|
||||
}
|
||||
|
||||
const CCB_TABLE_NAME = 'CHEM_COMP_BONDS';
|
||||
const CCA_TABLE_NAME = 'CHEM_COMP_ATOMS';
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Create a cif file with one big table of all chem_comp_bond entries from the CCD and PVCD.'
|
||||
});
|
||||
parser.add_argument('out', {
|
||||
help: 'Generated file output path.'
|
||||
});
|
||||
parser.add_argument('--forceDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of CCD and PVCD.'
|
||||
});
|
||||
parser.add_argument('--binary', '-b', {
|
||||
action: 'store_true',
|
||||
help: 'Output as BinaryCIF.'
|
||||
});
|
||||
parser.add_argument('--ccaOut', '-a', {
|
||||
help: 'Optional generated file output path for chem_comp_atom data.',
|
||||
required: false
|
||||
});
|
||||
interface Args {
|
||||
out: string,
|
||||
forceDownload?: boolean,
|
||||
binary?: boolean,
|
||||
ccaOut?: string
|
||||
}
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
run(args.out, args.binary, args.forceDownload, args.ccaOut);
|
||||
75
src/cli/chem-comp-dict/util.ts
Normal file
75
src/cli/chem-comp-dict/util.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import * as util from 'util';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as zlib from 'zlib';
|
||||
import fetch from 'node-fetch';
|
||||
require('util.promisify').shim();
|
||||
const readFile = util.promisify(fs.readFile);
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
|
||||
import { Progress } from '../../mol-task';
|
||||
import { Database } from '../../mol-data/db';
|
||||
import { CIF } from '../../mol-io/reader/cif';
|
||||
import { CifWriter } from '../../mol-io/writer/cif';
|
||||
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
|
||||
|
||||
export async function ensureAvailable(path: string, url: string, forceDownload = false) {
|
||||
if (forceDownload || !fs.existsSync(path)) {
|
||||
console.log(`downloading ${url}...`);
|
||||
const data = await fetch(url);
|
||||
if (!fs.existsSync(DATA_DIR)) {
|
||||
fs.mkdirSync(DATA_DIR);
|
||||
}
|
||||
if (url.endsWith('.gz')) {
|
||||
await writeFile(path, zlib.gunzipSync(await data.buffer()));
|
||||
} else {
|
||||
await writeFile(path, await data.text());
|
||||
}
|
||||
console.log(`done downloading ${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function ensureDataAvailable(forceDownload = false) {
|
||||
await ensureAvailable(CCD_PATH, CCD_URL, forceDownload);
|
||||
await ensureAvailable(PVCD_PATH, PVCD_URL, forceDownload);
|
||||
}
|
||||
|
||||
export async function readFileAsCollection<S extends Database.Schema>(path: string, schema: S) {
|
||||
const parsed = await parseCif(await readFile(path, 'utf8'));
|
||||
return CIF.toDatabaseCollection(schema, parsed.result);
|
||||
}
|
||||
|
||||
export async function readCCD() {
|
||||
return readFileAsCollection(CCD_PATH, CCD_Schema);
|
||||
}
|
||||
|
||||
export async function readPVCD() {
|
||||
return readFileAsCollection(PVCD_PATH, CCD_Schema);
|
||||
}
|
||||
|
||||
async function parseCif(data: string | Uint8Array) {
|
||||
const comp = CIF.parse(data);
|
||||
console.time('parse cif');
|
||||
const parsed = await comp.run(p => console.log(Progress.format(p)), 250);
|
||||
console.timeEnd('parse cif');
|
||||
if (parsed.isError) throw parsed;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export function getEncodedCif(name: string, database: Database<Database.Schema>, binary = false) {
|
||||
const encoder = CifWriter.createEncoder({ binary, encoderName: 'mol*' });
|
||||
CifWriter.Encoder.writeDatabase(encoder, name, database);
|
||||
return encoder.getData();
|
||||
}
|
||||
|
||||
const DATA_DIR = path.join(__dirname, '..', '..', '..', '..', 'build/data');
|
||||
const CCD_PATH = path.join(DATA_DIR, 'components.cif');
|
||||
const PVCD_PATH = path.join(DATA_DIR, 'aa-variants-v1.cif');
|
||||
const CCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif';
|
||||
const PVCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/aa-variants-v1.cif';
|
||||
119
src/cli/cif2bcif/converter.ts
Normal file
119
src/cli/cif2bcif/converter.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
|
||||
*/
|
||||
|
||||
import { CIF, CifCategory, getCifFieldType, CifField, CifFile } from '../../mol-io/reader/cif';
|
||||
import { CifWriter, EncodingStrategyHint } from '../../mol-io/writer/cif';
|
||||
import * as util from 'util';
|
||||
import * as fs from 'fs';
|
||||
import * as zlib from 'zlib';
|
||||
import { Progress, Task, RuntimeContext } from '../../mol-task';
|
||||
import { classifyFloatArray, classifyIntArray } from '../../mol-io/common/binary-cif';
|
||||
import { BinaryEncodingProvider } from '../../mol-io/writer/cif/encoder/binary';
|
||||
import { Category } from '../../mol-io/writer/cif/encoder';
|
||||
import { ReaderResult } from '../../mol-io/reader/result';
|
||||
|
||||
function showProgress(p: Progress) {
|
||||
process.stdout.write(`\r${new Array(80).join(' ')}`);
|
||||
process.stdout.write(`\r${Progress.format(p)}`);
|
||||
}
|
||||
|
||||
const readFileAsync = util.promisify(fs.readFile);
|
||||
const unzipAsync = util.promisify<zlib.InputType, Buffer>(zlib.unzip);
|
||||
|
||||
async function readFile(ctx: RuntimeContext, filename: string): Promise<ReaderResult<CifFile>> {
|
||||
const isGz = /\.gz$/i.test(filename);
|
||||
if (filename.match(/\.bcif/)) {
|
||||
let input = await readFileAsync(filename);
|
||||
if (isGz) input = await unzipAsync(input);
|
||||
return await CIF.parseBinary(new Uint8Array(input)).runInContext(ctx);
|
||||
} else {
|
||||
let str: string;
|
||||
if (isGz) {
|
||||
const data = await unzipAsync(await readFileAsync(filename));
|
||||
str = data.toString('utf8');
|
||||
} else {
|
||||
str = await readFileAsync(filename, 'utf8');
|
||||
}
|
||||
return await CIF.parseText(str).runInContext(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
async function getCIF(ctx: RuntimeContext, filename: string) {
|
||||
const parsed = await readFile(ctx, filename);
|
||||
if (parsed.isError) {
|
||||
throw new Error(parsed.toString());
|
||||
}
|
||||
return parsed.result;
|
||||
}
|
||||
|
||||
function getCategoryInstanceProvider(cat: CifCategory, fields: CifWriter.Field[]): CifWriter.Category {
|
||||
return {
|
||||
name: cat.name,
|
||||
instance: () => CifWriter.categoryInstance(fields, { data: cat, rowCount: cat.rowCount })
|
||||
};
|
||||
}
|
||||
|
||||
function classify(name: string, field: CifField): CifWriter.Field {
|
||||
const type = getCifFieldType(field);
|
||||
if (type['@type'] === 'str') {
|
||||
return { name, type: CifWriter.Field.Type.Str, value: field.str, valueKind: field.valueKind };
|
||||
} else if (type['@type'] === 'float') {
|
||||
const encoder = classifyFloatArray(field.toFloatArray({ array: Float64Array }));
|
||||
return CifWriter.Field.float(name, field.float, { valueKind: field.valueKind, encoder, typedArray: Float64Array });
|
||||
} else {
|
||||
const encoder = classifyIntArray(field.toIntArray({ array: Int32Array }));
|
||||
return CifWriter.Field.int(name, field.int, { valueKind: field.valueKind, encoder, typedArray: Int32Array });
|
||||
}
|
||||
}
|
||||
|
||||
export function convert(path: string, asText = false, hints?: EncodingStrategyHint[], filter?: string) {
|
||||
return Task.create<Uint8Array>('BinaryCIF', async ctx => {
|
||||
const encodingProvider: BinaryEncodingProvider = hints
|
||||
? CifWriter.createEncodingProviderFromJsonConfig(hints)
|
||||
: { get: (c, f) => void 0 };
|
||||
const cif = await getCIF(ctx, path);
|
||||
|
||||
const encoder = CifWriter.createEncoder({
|
||||
binary: !asText,
|
||||
encoderName: 'mol*/ciftools cif2bcif',
|
||||
binaryAutoClassifyEncoding: true,
|
||||
binaryEncodingPovider: encodingProvider
|
||||
});
|
||||
|
||||
if (filter) {
|
||||
encoder.setFilter(Category.filterOf(filter));
|
||||
}
|
||||
|
||||
let maxProgress = 0;
|
||||
for (const b of cif.blocks) {
|
||||
maxProgress += b.categoryNames.length;
|
||||
for (const c of b.categoryNames) maxProgress += b.categories[c].fieldNames.length;
|
||||
}
|
||||
|
||||
let current = 0;
|
||||
for (const b of cif.blocks) {
|
||||
encoder.startDataBlock(b.header);
|
||||
for (const c of b.categoryNames) {
|
||||
const cat = b.categories[c];
|
||||
const fields: CifWriter.Field[] = [];
|
||||
for (const f of cat.fieldNames) {
|
||||
fields.push(classify(f, cat.getField(f)!));
|
||||
current++;
|
||||
if (ctx.shouldUpdate) await ctx.update({ message: 'Encoding...', current, max: maxProgress });
|
||||
}
|
||||
|
||||
encoder.writeCategory(getCategoryInstanceProvider(b.categories[c], fields));
|
||||
current++;
|
||||
if (ctx.shouldUpdate) await ctx.update({ message: 'Encoding...', current, max: maxProgress });
|
||||
}
|
||||
}
|
||||
await ctx.update('Exporting...');
|
||||
const ret = encoder.getData() as Uint8Array;
|
||||
await ctx.update('Done.\n');
|
||||
return ret;
|
||||
}).run(showProgress, 250);
|
||||
}
|
||||
68
src/cli/cif2bcif/index.ts
Normal file
68
src/cli/cif2bcif/index.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as util from 'util';
|
||||
import * as fs from 'fs';
|
||||
import * as zlib from 'zlib';
|
||||
import { convert } from './converter';
|
||||
|
||||
require('util.promisify').shim();
|
||||
|
||||
async function process(srcPath: string, outPath: string, configPath?: string, filterPath?: string) {
|
||||
const config = configPath ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : void 0;
|
||||
const filter = filterPath ? fs.readFileSync(filterPath, 'utf8') : void 0;
|
||||
|
||||
const res = await convert(srcPath, false, config, filter);
|
||||
await write(outPath, res);
|
||||
}
|
||||
|
||||
const zipAsync = util.promisify<zlib.InputType, Buffer>(zlib.gzip);
|
||||
|
||||
async function write(outPath: string, res: Uint8Array) {
|
||||
const isGz = /\.gz$/i.test(outPath);
|
||||
if (isGz) {
|
||||
res = await zipAsync(res);
|
||||
}
|
||||
fs.writeFileSync(outPath, res);
|
||||
}
|
||||
|
||||
function run(args: Args) {
|
||||
process(args.src, args.out, args.config, args.filter);
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Convert any CIF file to a BCIF file'
|
||||
});
|
||||
parser.add_argument('src', {
|
||||
help: 'Source CIF path'
|
||||
});
|
||||
parser.add_argument('out', {
|
||||
help: 'Output BCIF path'
|
||||
});
|
||||
parser.add_argument('-c', '--config', {
|
||||
help: 'Optional encoding strategy/precision config path',
|
||||
required: false
|
||||
});
|
||||
parser.add_argument('-f', '--filter', {
|
||||
help: 'Optional filter whitelist/blacklist path',
|
||||
required: false
|
||||
});
|
||||
|
||||
interface Args {
|
||||
src: string
|
||||
out: string
|
||||
config?: string
|
||||
filter?: string
|
||||
}
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
if (args) {
|
||||
run(args);
|
||||
}
|
||||
275
src/cli/cifschema/index.ts
Normal file
275
src/cli/cifschema/index.ts
Normal file
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
import { parseCsv } from '../../mol-io/reader/csv/parser';
|
||||
import { CifFrame, CifBlock } from '../../mol-io/reader/cif';
|
||||
import { parseCifText } from '../../mol-io/reader/cif/text/parser';
|
||||
import { generateSchema } from './util/cif-dic';
|
||||
import { generate } from './util/generate';
|
||||
import { Filter, Database } from './util/schema';
|
||||
import { parseImportGet } from './util/helper';
|
||||
|
||||
function getDicVersion(block: CifBlock) {
|
||||
return block.categories.dictionary.getField('version')!.str(0);
|
||||
}
|
||||
|
||||
function getDicNamespace(block: CifBlock) {
|
||||
return block.categories.dictionary.getField('namespace')!.str(0);
|
||||
}
|
||||
|
||||
async function runGenerateSchemaMmcif(name: string, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
|
||||
await ensureMmcifDicAvailable();
|
||||
const mmcifDic = await parseCifText(fs.readFileSync(MMCIF_DIC_PATH, 'utf8')).run();
|
||||
if (mmcifDic.isError) throw mmcifDic;
|
||||
|
||||
await ensureIhmDicAvailable();
|
||||
const ihmDic = await parseCifText(fs.readFileSync(IHM_DIC_PATH, 'utf8')).run();
|
||||
if (ihmDic.isError) throw ihmDic;
|
||||
|
||||
await ensureCarbBranchDicAvailable();
|
||||
const carbBranchDic = await parseCifText(fs.readFileSync(CARB_BRANCH_DIC_PATH, 'utf8')).run();
|
||||
if (carbBranchDic.isError) throw carbBranchDic;
|
||||
|
||||
await ensureCarbCompDicAvailable();
|
||||
const carbCompDic = await parseCifText(fs.readFileSync(CARB_COMP_DIC_PATH, 'utf8')).run();
|
||||
if (carbCompDic.isError) throw carbCompDic;
|
||||
|
||||
const mmcifDicVersion = getDicVersion(mmcifDic.result.blocks[0]);
|
||||
const ihmDicVersion = getDicVersion(ihmDic.result.blocks[0]);
|
||||
const carbDicVersion = 'draft';
|
||||
const version = `Dictionary versions: mmCIF ${mmcifDicVersion}, IHM ${ihmDicVersion}, CARB ${carbDicVersion}.`;
|
||||
|
||||
const frames: CifFrame[] = [...mmcifDic.result.blocks[0].saveFrames, ...ihmDic.result.blocks[0].saveFrames, ...carbBranchDic.result.blocks[0].saveFrames, ...carbCompDic.result.blocks[0].saveFrames];
|
||||
const schema = generateSchema(frames);
|
||||
|
||||
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
|
||||
}
|
||||
|
||||
async function runGenerateSchemaCifCore(name: string, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
|
||||
await ensureCifCoreDicAvailable();
|
||||
const cifCoreDic = await parseCifText(fs.readFileSync(CIF_CORE_DIC_PATH, 'utf8')).run();
|
||||
if (cifCoreDic.isError) throw cifCoreDic;
|
||||
|
||||
const cifCoreDicVersion = getDicVersion(cifCoreDic.result.blocks[0]);
|
||||
const version = `Dictionary versions: CifCore ${cifCoreDicVersion}.`;
|
||||
|
||||
const frames: CifFrame[] = [...cifCoreDic.result.blocks[0].saveFrames];
|
||||
const imports = await resolveImports(frames, DIC_DIR);
|
||||
const schema = generateSchema(frames, imports);
|
||||
|
||||
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
|
||||
}
|
||||
|
||||
async function resolveImports(frames: CifFrame[], baseDir: string): Promise<Map<string, CifFrame[]>> {
|
||||
const imports = new Map<string, CifFrame[]>();
|
||||
|
||||
for (const d of frames) {
|
||||
if ('import' in d.categories) {
|
||||
const importGet = parseImportGet(d.categories['import'].getField('get')!.str(0));
|
||||
for (const g of importGet) {
|
||||
const { file } = g;
|
||||
if (!file) continue;
|
||||
if (imports.has(file)) continue;
|
||||
|
||||
const dic = await parseCifText(fs.readFileSync(path.join(baseDir, file), 'utf8')).run();
|
||||
if (dic.isError) throw dic;
|
||||
|
||||
imports.set(file, [...dic.result.blocks[0].saveFrames]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
async function runGenerateSchemaDic(name: string, dicPath: string, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
|
||||
const dic = await parseCifText(fs.readFileSync(dicPath, 'utf8')).run();
|
||||
if (dic.isError) throw dic;
|
||||
|
||||
const dicVersion = getDicVersion(dic.result.blocks[0]);
|
||||
const dicName = getDicNamespace(dic.result.blocks[0]);
|
||||
const version = `Dictionary versions: ${dicName} ${dicVersion}.`;
|
||||
|
||||
const frames: CifFrame[] = [...dic.result.blocks[0].saveFrames];
|
||||
const imports = await resolveImports(frames, path.dirname(dicPath));
|
||||
const schema = generateSchema(frames, imports);
|
||||
|
||||
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
|
||||
}
|
||||
|
||||
async function runGenerateSchema(name: string, version: string, schema: Database, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
|
||||
const filter = fieldNamesPath ? await getFieldNamesFilter(fieldNamesPath) : undefined;
|
||||
const output = typescript ? generate(name, version, schema, filter, moldbImportPath, addAliases) : JSON.stringify(schema, undefined, 4);
|
||||
|
||||
if (out) {
|
||||
fs.writeFileSync(out, output);
|
||||
} else {
|
||||
console.log(output);
|
||||
}
|
||||
}
|
||||
|
||||
async function getFieldNamesFilter(fieldNamesPath: string): Promise<Filter> {
|
||||
const fieldNamesStr = fs.readFileSync(fieldNamesPath, 'utf8');
|
||||
const parsed = await parseCsv(fieldNamesStr, { noColumnNames: true }).run();
|
||||
if (parsed.isError) throw parser.error;
|
||||
const csvFile = parsed.result;
|
||||
|
||||
const fieldNamesCol = csvFile.table.getColumn('0');
|
||||
if (!fieldNamesCol) throw new Error('error getting fields columns');
|
||||
const fieldNames = fieldNamesCol.toStringArray();
|
||||
|
||||
const filter: Filter = {};
|
||||
fieldNames.forEach((name, i) => {
|
||||
const [category, field] = name.split('.');
|
||||
// console.log(category, field)
|
||||
if (!filter[category]) filter[category] = {};
|
||||
filter[category][field] = true;
|
||||
});
|
||||
return filter;
|
||||
}
|
||||
|
||||
async function ensureMmcifDicAvailable() { await ensureDicAvailable(MMCIF_DIC_PATH, MMCIF_DIC_URL); }
|
||||
async function ensureIhmDicAvailable() { await ensureDicAvailable(IHM_DIC_PATH, IHM_DIC_URL); }
|
||||
async function ensureCarbBranchDicAvailable() { await ensureDicAvailable(CARB_BRANCH_DIC_PATH, CARB_BRANCH_DIC_URL); }
|
||||
async function ensureCarbCompDicAvailable() { await ensureDicAvailable(CARB_COMP_DIC_PATH, CARB_COMP_DIC_URL); }
|
||||
async function ensureCifCoreDicAvailable() {
|
||||
await ensureDicAvailable(CIF_CORE_DIC_PATH, CIF_CORE_DIC_URL);
|
||||
await ensureDicAvailable(CIF_CORE_ENUM_PATH, CIF_CORE_ENUM_URL);
|
||||
await ensureDicAvailable(CIF_CORE_ATTR_PATH, CIF_CORE_ATTR_URL);
|
||||
}
|
||||
|
||||
async function ensureDicAvailable(dicPath: string, dicUrl: string) {
|
||||
if (FORCE_DIC_DOWNLOAD || !fs.existsSync(dicPath)) {
|
||||
const name = dicUrl.substr(dicUrl.lastIndexOf('/') + 1);
|
||||
console.log(`downloading ${name}...`);
|
||||
const data = await fetch(dicUrl);
|
||||
if (!fs.existsSync(DIC_DIR)) {
|
||||
fs.mkdirSync(DIC_DIR);
|
||||
}
|
||||
fs.writeFileSync(dicPath, await data.text());
|
||||
console.log(`done downloading ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
const DIC_DIR = path.resolve(__dirname, '../../../../build/dics/');
|
||||
const MMCIF_DIC_PATH = `${DIC_DIR}/mmcif_pdbx_v50.dic`;
|
||||
const MMCIF_DIC_URL = 'http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic';
|
||||
const IHM_DIC_PATH = `${DIC_DIR}/ihm-extension.dic`;
|
||||
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHM-dictionary/master/ihm-extension.dic';
|
||||
const CARB_BRANCH_DIC_PATH = `${DIC_DIR}/entity_branch-extension.dic`;
|
||||
const CARB_BRANCH_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/entity_branch-extension.dic';
|
||||
const CARB_COMP_DIC_PATH = `${DIC_DIR}/chem_comp-extension.dic`;
|
||||
const CARB_COMP_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/chem_comp-extension.dic';
|
||||
|
||||
const CIF_CORE_DIC_PATH = `${DIC_DIR}/cif_core.dic`;
|
||||
const CIF_CORE_DIC_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/cif_core.dic';
|
||||
const CIF_CORE_ENUM_PATH = `${DIC_DIR}/templ_enum.cif`;
|
||||
const CIF_CORE_ENUM_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/templ_enum.cif';
|
||||
const CIF_CORE_ATTR_PATH = `${DIC_DIR}/templ_attr.cif`;
|
||||
const CIF_CORE_ATTR_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/templ_attr.cif';
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Create schema from mmcif dictionary (v50 plus IHM and entity_branch extensions, downloaded from wwPDB)'
|
||||
});
|
||||
parser.add_argument('--preset', '-p', {
|
||||
default: '',
|
||||
choices: ['', 'mmCIF', 'CCD', 'BIRD', 'CifCore'],
|
||||
help: 'Preset name'
|
||||
});
|
||||
parser.add_argument('--name', '-n', {
|
||||
default: '',
|
||||
help: 'Schema name'
|
||||
});
|
||||
parser.add_argument('--out', '-o', {
|
||||
help: 'Generated schema output path, if not given printed to stdout'
|
||||
});
|
||||
parser.add_argument('--targetFormat', '-tf', {
|
||||
default: 'typescript-molstar',
|
||||
choices: ['typescript-molstar', 'json-internal'],
|
||||
help: 'Target format'
|
||||
});
|
||||
parser.add_argument('--dicPath', '-d', {
|
||||
default: '',
|
||||
help: 'Path to dictionary'
|
||||
});
|
||||
parser.add_argument('--fieldNamesPath', '-fn', {
|
||||
default: '',
|
||||
help: 'Field names to include'
|
||||
});
|
||||
parser.add_argument('--forceDicDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of dictionaries'
|
||||
});
|
||||
parser.add_argument('--moldataImportPath', '-mip', {
|
||||
default: 'molstar/lib/mol-data',
|
||||
help: 'mol-data import path (for typescript target only)'
|
||||
});
|
||||
parser.add_argument('--addAliases', '-aa', {
|
||||
action: 'store_true',
|
||||
help: 'Add field name/path aliases'
|
||||
});
|
||||
interface Args {
|
||||
name: string
|
||||
preset: '' | 'mmCIF' | 'CCD' | 'BIRD' | 'CifCore'
|
||||
forceDicDownload: boolean
|
||||
dic: '' | 'mmCIF' | 'CifCore'
|
||||
dicPath: string,
|
||||
fieldNamesPath: string
|
||||
targetFormat: 'typescript-molstar' | 'json-internal'
|
||||
out: string,
|
||||
moldataImportPath: string
|
||||
addAliases: boolean
|
||||
}
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
const FORCE_DIC_DOWNLOAD = args.forceDicDownload;
|
||||
|
||||
switch (args.preset) {
|
||||
case 'mmCIF':
|
||||
args.name = 'mmCIF';
|
||||
args.dic = 'mmCIF';
|
||||
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/mmcif-field-names.csv');
|
||||
break;
|
||||
case 'CCD':
|
||||
args.name = 'CCD';
|
||||
args.dic = 'mmCIF';
|
||||
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/ccd-field-names.csv');
|
||||
break;
|
||||
case 'BIRD':
|
||||
args.name = 'BIRD';
|
||||
args.dic = 'mmCIF';
|
||||
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/bird-field-names.csv');
|
||||
break;
|
||||
case 'CifCore':
|
||||
args.name = 'CifCore';
|
||||
args.dic = 'CifCore';
|
||||
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/cif-core-field-names.csv');
|
||||
break;
|
||||
}
|
||||
|
||||
if (args.name) {
|
||||
const typescript = args.targetFormat === 'typescript-molstar';
|
||||
if (args.dicPath) {
|
||||
runGenerateSchemaDic(args.name, args.dicPath, args.fieldNamesPath, typescript, args.out, args.moldataImportPath, args.addAliases).catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
} else if (args.dic === 'mmCIF') {
|
||||
runGenerateSchemaMmcif(args.name, args.fieldNamesPath, typescript, args.out, args.moldataImportPath, args.addAliases).catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
} else if (args.dic === 'CifCore') {
|
||||
runGenerateSchemaCifCore(args.name, args.fieldNamesPath, typescript, args.out, args.moldataImportPath, args.addAliases).catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
475
src/cli/cifschema/util/cif-dic.ts
Normal file
475
src/cli/cifschema/util/cif-dic.ts
Normal file
@@ -0,0 +1,475 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Database, Column, EnumCol, StrCol, IntCol, ListCol, FloatCol, CoordCol, MatrixCol, VectorCol } from './schema';
|
||||
import { parseImportGet } from './helper';
|
||||
import * as Data from '../../../mol-io/reader/cif/data-model';
|
||||
import { CifFrame } from '../../../mol-io/reader/cif/data-model';
|
||||
|
||||
export function getFieldType(type: string, description: string, values?: string[], container?: string): Column {
|
||||
switch (type) {
|
||||
// mmCIF
|
||||
case 'code':
|
||||
case 'ucode':
|
||||
case 'line':
|
||||
case 'uline':
|
||||
case 'text':
|
||||
case 'char':
|
||||
case 'uchar3':
|
||||
case 'uchar1':
|
||||
case 'boolean':
|
||||
return values && values.length ? EnumCol(values, 'str', description) : StrCol(description);
|
||||
case 'aliasname':
|
||||
case 'name':
|
||||
case 'idname':
|
||||
case 'any':
|
||||
case 'atcode':
|
||||
case 'fax':
|
||||
case 'phone':
|
||||
case 'email':
|
||||
case 'code30':
|
||||
case 'seq-one-letter-code':
|
||||
case 'author':
|
||||
case 'orcid_id':
|
||||
case 'pdbx_PDB_obsoleted_db_id':
|
||||
case 'pdbx_related_db_id':
|
||||
case 'sequence_dep':
|
||||
case 'pdb_id':
|
||||
case 'emd_id':
|
||||
// todo, consider adding specialised fields
|
||||
case 'yyyy-mm-dd':
|
||||
case 'yyyy-mm-dd:hh:mm':
|
||||
case 'yyyy-mm-dd:hh:mm-flex':
|
||||
case 'int-range':
|
||||
case 'float-range':
|
||||
case 'binary':
|
||||
case 'operation_expression':
|
||||
case 'point_symmetry':
|
||||
case '4x3_matrix':
|
||||
case '3x4_matrices':
|
||||
case 'point_group':
|
||||
case 'point_group_helical':
|
||||
case 'symmetry_operation':
|
||||
case 'date_dep':
|
||||
case 'url':
|
||||
case 'symop':
|
||||
case 'exp_data_doi':
|
||||
case 'asym_id':
|
||||
return StrCol(description);
|
||||
case 'int':
|
||||
case 'non_negative_int':
|
||||
case 'positive_int':
|
||||
return values && values.length ? EnumCol(values, 'int', description) : IntCol(description);
|
||||
case 'float':
|
||||
return FloatCol(description);
|
||||
case 'ec-type':
|
||||
case 'ucode-alphanum-csv':
|
||||
case 'id_list':
|
||||
return ListCol('str', ',', description);
|
||||
case 'id_list_spc':
|
||||
return ListCol('str', ' ', description);
|
||||
|
||||
// cif
|
||||
case 'Text':
|
||||
case 'Code':
|
||||
case 'Complex':
|
||||
case 'Symop':
|
||||
case 'List':
|
||||
case 'List(Real,Real)':
|
||||
case 'List(Real,Real,Real,Real)':
|
||||
case 'Date':
|
||||
case 'DateTime':
|
||||
case 'Tag':
|
||||
case 'Implied':
|
||||
case 'Word':
|
||||
return wrapContainer('str', ',', description, container);
|
||||
case 'Real':
|
||||
return wrapContainer('float', ',', description, container);
|
||||
case 'Integer':
|
||||
return wrapContainer('int', ',', description, container);
|
||||
|
||||
}
|
||||
console.log(`unknown type '${type}'`);
|
||||
return StrCol(description);
|
||||
}
|
||||
|
||||
function ColFromType(type: 'int' | 'str' | 'float' | 'coord', description: string): Column {
|
||||
switch (type) {
|
||||
case 'int': return IntCol(description);
|
||||
case 'str': return StrCol(description);
|
||||
case 'float': return FloatCol(description);
|
||||
case 'coord': return CoordCol(description);
|
||||
}
|
||||
}
|
||||
|
||||
function wrapContainer(type: 'int' | 'str' | 'float' | 'coord', separator: string, description: string, container?: string) {
|
||||
return container && container === 'List' ? ListCol(type, separator, description) : ColFromType(type, description);
|
||||
}
|
||||
|
||||
type FrameCategories = { [category: string]: Data.CifFrame }
|
||||
type FrameLinks = { [k: string]: string }
|
||||
|
||||
interface FrameData {
|
||||
categories: FrameCategories
|
||||
links: FrameLinks
|
||||
}
|
||||
|
||||
type Imports = Map<string, CifFrame[]>
|
||||
|
||||
function getImportFrames(d: Data.CifFrame, imports: Imports) {
|
||||
const frames: Data.CifFrame[] = [];
|
||||
if (!('import' in d.categories)) return frames;
|
||||
|
||||
const importGet = parseImportGet(d.categories['import'].getField('get')!.str(0));
|
||||
for (const g of importGet) {
|
||||
const { file, save } = g;
|
||||
if (!file || !save) {
|
||||
console.warn(`missing 'save' or 'file' for import in '${d.header}'`);
|
||||
continue;
|
||||
}
|
||||
const importFrames = imports.get(file);
|
||||
if (!importFrames) {
|
||||
console.warn(`missing '${file}' entry in imports`);
|
||||
continue;
|
||||
}
|
||||
const importSave = importFrames.find(id => id.header.toLowerCase() === save.toLowerCase());
|
||||
if (!importSave) {
|
||||
console.warn(`missing '${save}' save frame in '${file}'`);
|
||||
continue;
|
||||
}
|
||||
|
||||
frames.push(importSave);
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
/** get field from given or linked category */
|
||||
function getField(category: string, field: string, d: Data.CifFrame, imports: Imports, ctx: FrameData): Data.CifField|undefined {
|
||||
const { categories, links } = ctx;
|
||||
const cat = d.categories[category];
|
||||
if (cat) {
|
||||
return cat.getField(field);
|
||||
} else if (d.header in links) {
|
||||
const linkName = links[d.header];
|
||||
if (linkName in categories) {
|
||||
return getField(category, field, categories[linkName], imports, ctx);
|
||||
} else {
|
||||
// console.log(`link '${linkName}' not found`)
|
||||
}
|
||||
} else {
|
||||
const importFrames = getImportFrames(d, imports);
|
||||
for (const idf of importFrames) {
|
||||
return getField(category, field, idf, imports, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEnums(d: Data.CifFrame, imports: Imports, ctx: FrameData) {
|
||||
const value = getField('item_enumeration', 'value', d, imports, ctx);
|
||||
const enums: string[] = [];
|
||||
if (value) {
|
||||
for (let i = 0; i < value.rowCount; ++i) {
|
||||
enums.push(value.str(i));
|
||||
// console.log(value.str(i))
|
||||
}
|
||||
return enums;
|
||||
} else {
|
||||
// console.log(`item_enumeration.value not found for '${d.header}'`)
|
||||
}
|
||||
}
|
||||
|
||||
function getContainer(d: Data.CifFrame, imports: Imports, ctx: FrameData) {
|
||||
const value = getField('type', 'container', d, imports, ctx);
|
||||
return value ? value.str(0) : undefined;
|
||||
}
|
||||
|
||||
function getCode(d: Data.CifFrame, imports: Imports, ctx: FrameData): [string, string[] | undefined, string | undefined ] | undefined {
|
||||
const code = getField('item_type', 'code', d, imports, ctx) || getField('type', 'contents', d, imports, ctx);
|
||||
if (code) {
|
||||
return [code.str(0), getEnums(d, imports, ctx), getContainer(d, imports, ctx)];
|
||||
} else {
|
||||
console.log(`item_type.code or type.contents not found for '${d.header}'`);
|
||||
}
|
||||
}
|
||||
|
||||
function getSubCategory(d: Data.CifFrame, imports: Imports, ctx: FrameData): string | undefined {
|
||||
const value = getField('item_sub_category', 'id', d, imports, ctx);
|
||||
if (value) {
|
||||
return value.str(0);
|
||||
}
|
||||
}
|
||||
|
||||
function getDescription(d: Data.CifFrame, imports: Imports, ctx: FrameData): string | undefined {
|
||||
const value = getField('item_description', 'description', d, imports, ctx) || getField('description', 'text', d, imports, ctx);
|
||||
if (value) {
|
||||
// trim (after newlines) and remove references to square brackets
|
||||
return value.str(0).trim()
|
||||
.replace(/(\r\n|\r|\n)([ \t]+)/g, '\n')
|
||||
.replace(/(\[[1-3]\])+ element/, 'elements')
|
||||
.replace(/(\[[1-3]\])+/, '');
|
||||
}
|
||||
}
|
||||
|
||||
function getAliases(d: Data.CifFrame, imports: Imports, ctx: FrameData): string[] | undefined {
|
||||
const value = getField('item_aliases', 'alias_name', d, imports, ctx) || getField('alias', 'definition_id', d, imports, ctx);
|
||||
return value ? value.toStringArray().map(v => v.substr(1)) : undefined;
|
||||
}
|
||||
|
||||
const reMatrixField = /\[[1-3]\]\[[1-3]\]/;
|
||||
const reVectorField = /\[[1-3]\]/;
|
||||
|
||||
const FORCE_INT_FIELDS = [
|
||||
'_atom_site.id',
|
||||
'_atom_site.auth_seq_id',
|
||||
'_atom_site_anisotrop.id',
|
||||
'_pdbx_struct_mod_residue.auth_seq_id',
|
||||
'_struct_conf.beg_auth_seq_id',
|
||||
'_struct_conf.end_auth_seq_id',
|
||||
'_struct_conn.ptnr1_auth_seq_id',
|
||||
'_struct_conn.ptnr2_auth_seq_id',
|
||||
'_struct_sheet_range.beg_auth_seq_id',
|
||||
'_struct_sheet_range.end_auth_seq_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Note that name and mapped name must share a prefix. This is not always the case in
|
||||
* the cifCore dictionary, but for downstream code to work a container field with the
|
||||
* same prefix as the member fields must be given here and in the field names filter
|
||||
* list.
|
||||
*/
|
||||
const FORCE_MATRIX_FIELDS_MAP: { [k: string]: string } = {
|
||||
'atom_site_aniso.u_11': 'u', // is matrix_u in the the dic
|
||||
'atom_site_aniso.u_22': 'u',
|
||||
'atom_site_aniso.u_33': 'u',
|
||||
'atom_site_aniso.u_23': 'u',
|
||||
'atom_site_aniso.u_13': 'u',
|
||||
'atom_site_aniso.u_12': 'u',
|
||||
};
|
||||
const FORCE_MATRIX_FIELDS = Object.keys(FORCE_MATRIX_FIELDS_MAP);
|
||||
|
||||
const EXTRA_ALIASES: Database['aliases'] = {
|
||||
'atom_site_aniso.matrix_u': [
|
||||
'atom_site_anisotrop_U',
|
||||
'atom_site_aniso.U'
|
||||
],
|
||||
};
|
||||
|
||||
const COMMA_SEPARATED_LIST_FIELDS = [
|
||||
'_atom_site.pdbx_struct_group_id',
|
||||
'_chem_comp.mon_nstd_parent_comp_id',
|
||||
'_diffrn_radiation.pdbx_wavelength_list',
|
||||
'_diffrn_source.pdbx_wavelength_list',
|
||||
'_em_diffraction.tilt_angle_list', // 20,40,50,55
|
||||
'_em_entity_assembly.entity_id_list',
|
||||
'_entity.pdbx_description', // Endolysin,Beta-2 adrenergic receptor
|
||||
'_entity.pdbx_ec',
|
||||
'_entity_poly.pdbx_strand_id', // A,B
|
||||
'_entity_src_gen.pdbx_gene_src_gene', // ADRB2, ADRB2R, B2AR
|
||||
'_pdbx_depui_entry_details.experimental_methods',
|
||||
'_pdbx_depui_entry_details.requested_accession_types',
|
||||
'_pdbx_soln_scatter_model.software_list', // INSIGHT II, HOMOLOGY, DISCOVERY, BIOPOLYMER, DELPHI
|
||||
'_pdbx_soln_scatter_model.software_author_list', // MSI
|
||||
'_pdbx_soln_scatter_model.entry_fitting_list', // Odd example: 'PDB CODE 1HFI, 1HCC, 1HFH, 1VCC'
|
||||
'_pdbx_struct_assembly_gen.entity_inst_id',
|
||||
'_pdbx_struct_assembly_gen.asym_id_list',
|
||||
'_pdbx_struct_assembly_gen.auth_asym_id_list',
|
||||
'_pdbx_struct_assembly_gen_depositor_info.asym_id_list',
|
||||
'_pdbx_struct_assembly_gen_depositor_info.chain_id_list',
|
||||
'_pdbx_struct_group_list.group_enumeration_type',
|
||||
'_reflns.pdbx_diffrn_id',
|
||||
'_refine.pdbx_diffrn_id',
|
||||
'_reflns_shell.pdbx_diffrn_id',
|
||||
'_struct_keywords.text',
|
||||
];
|
||||
|
||||
const SPACE_SEPARATED_LIST_FIELDS = [
|
||||
'_chem_comp.pdbx_subcomponent_list', // TSM DPH HIS CHF EMR
|
||||
'_pdbx_soln_scatter.data_reduction_software_list', // OTOKO
|
||||
'_pdbx_soln_scatter.data_analysis_software_list', // SCTPL5 GNOM
|
||||
];
|
||||
|
||||
const SEMICOLON_SEPARATED_LIST_FIELDS = [
|
||||
'_chem_comp.pdbx_synonyms' // GLYCERIN; PROPANE-1,2,3-TRIOL
|
||||
];
|
||||
|
||||
/**
|
||||
* Useful when a dictionary extension will add enum values to an existing dictionary.
|
||||
* By adding them here, the dictionary extension can be tested before the added enum
|
||||
* values are available in the existing dictionary.
|
||||
*/
|
||||
const EXTRA_ENUM_VALUES: { [k: string]: string[] } = {
|
||||
|
||||
};
|
||||
|
||||
export function generateSchema(frames: CifFrame[], imports: Imports = new Map()): Database {
|
||||
const tables: Database['tables'] = {};
|
||||
const aliases: Database['aliases'] = { ...EXTRA_ALIASES };
|
||||
|
||||
const categories: FrameCategories = {};
|
||||
const links: FrameLinks = {};
|
||||
const ctx = { categories, links };
|
||||
|
||||
// get category metadata
|
||||
frames.forEach(d => {
|
||||
// category definitions in mmCIF start with '_' and don't include a '.'
|
||||
// category definitions in cifCore don't include a '.'
|
||||
if (d.header[0] === '_' || d.header.includes('.')) return;
|
||||
const categoryName = d.header.toLowerCase();
|
||||
// console.log(d.header, d.categoryNames, d.categories)
|
||||
let descriptionField: Data.CifField | undefined;
|
||||
const categoryKeyNames = new Set<string>();
|
||||
|
||||
if ('category' in d.categories && 'category_key' in d.categories) {
|
||||
const category = d.categories['category'];
|
||||
const categoryKey = d.categories['category_key'];
|
||||
if (categoryKey) {
|
||||
const categoryKey_names = categoryKey.getField('name');
|
||||
if (categoryKey_names) {
|
||||
for (let i = 0, il = categoryKey_names.rowCount; i < il; ++i) {
|
||||
categoryKeyNames.add(categoryKey_names.str(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
descriptionField = category.getField('description');
|
||||
|
||||
if (categoryKeyNames.size === 0) {
|
||||
console.log(`no key given for category '${categoryName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
if ('description' in d.categories) {
|
||||
descriptionField = d.categories['description'].getField('text');
|
||||
}
|
||||
|
||||
let description = '';
|
||||
if (descriptionField) {
|
||||
description = descriptionField.str(0).trim()
|
||||
.replace(/(\r\n|\r|\n)([ \t]+)/g, '\n'); // remove padding after newlines
|
||||
} else {
|
||||
console.log(`no description given for category '${categoryName}'`);
|
||||
}
|
||||
|
||||
tables[categoryName] = { description, key: categoryKeyNames, columns: {} };
|
||||
|
||||
// console.log('++++++++++++++++++++++++++++++++++++++++++')
|
||||
// console.log('name', categoryName)
|
||||
// console.log('desc', description)
|
||||
// console.log('key', categoryKeyNames)
|
||||
});
|
||||
|
||||
// build list of links between categories
|
||||
frames.forEach(d => {
|
||||
if (d.header[0] !== '_' && !d.header.includes('.')) return;
|
||||
categories[d.header] = d;
|
||||
const item_linked = d.categories['item_linked'];
|
||||
if (item_linked) {
|
||||
const child_name = item_linked.getField('child_name');
|
||||
const parent_name = item_linked.getField('parent_name');
|
||||
if (child_name && parent_name) {
|
||||
for (let i = 0; i < item_linked.rowCount; ++i) {
|
||||
const childName: string = child_name.str(i);
|
||||
const parentName = parent_name.str(i);
|
||||
if (childName in links && links[childName] !== parentName) {
|
||||
console.log(`${childName} linked to ${links[childName]}, ignoring link to ${parentName}`);
|
||||
}
|
||||
links[childName] = parentName;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// get field data
|
||||
Object.keys(categories).forEach(fullName => {
|
||||
const d = categories[fullName];
|
||||
if (!d) {
|
||||
console.log(`'${fullName}' not found, moving on`);
|
||||
return;
|
||||
}
|
||||
|
||||
const categoryName = d.header.substring(d.header[0] === '_' ? 1 : 0, d.header.indexOf('.'));
|
||||
const itemName = d.header.substring(d.header.indexOf('.') + 1);
|
||||
let fields: { [k: string]: Column };
|
||||
if (categoryName in tables) {
|
||||
fields = tables[categoryName].columns;
|
||||
tables[categoryName].key.add(itemName);
|
||||
} else if (categoryName.toLowerCase() in tables) {
|
||||
// take case from category name in 'field' data as it is better if data is from cif dictionaries
|
||||
tables[categoryName] = tables[categoryName.toLowerCase()];
|
||||
fields = tables[categoryName].columns;
|
||||
} else {
|
||||
console.log(`category '${categoryName}' has no metadata`);
|
||||
fields = {};
|
||||
tables[categoryName] = {
|
||||
description: '',
|
||||
key: new Set(),
|
||||
columns: fields
|
||||
};
|
||||
}
|
||||
|
||||
const itemAliases = getAliases(d, imports, ctx);
|
||||
if (itemAliases) aliases[`${categoryName}.${itemName}`] = itemAliases;
|
||||
|
||||
const description = getDescription(d, imports, ctx) || '';
|
||||
|
||||
// need to use regex to check for matrix or vector items
|
||||
// as sub_category assignment is missing for some entries
|
||||
const subCategory = getSubCategory(d, imports, ctx);
|
||||
if (subCategory === 'cartesian_coordinate' || subCategory === 'fractional_coordinate') {
|
||||
fields[itemName] = CoordCol(description);
|
||||
} else if (FORCE_INT_FIELDS.includes(d.header)) {
|
||||
fields[itemName] = IntCol(description);
|
||||
console.log(`forcing int: ${d.header}`);
|
||||
} else if (FORCE_MATRIX_FIELDS.includes(d.header)) {
|
||||
fields[itemName] = FloatCol(description);
|
||||
fields[FORCE_MATRIX_FIELDS_MAP[d.header]] = MatrixCol(3, 3, description);
|
||||
console.log(`forcing matrix: ${d.header}`);
|
||||
} else if (subCategory === 'matrix') {
|
||||
fields[itemName.replace(reMatrixField, '')] = MatrixCol(3, 3, description);
|
||||
} else if (subCategory === 'vector') {
|
||||
fields[itemName.replace(reVectorField, '')] = VectorCol(3, description);
|
||||
} else {
|
||||
if (itemName.match(reMatrixField)) {
|
||||
fields[itemName.replace(reMatrixField, '')] = MatrixCol(3, 3, description);
|
||||
console.log(`${d.header} should have 'matrix' _item_sub_category.id`);
|
||||
} else if (itemName.match(reVectorField)) {
|
||||
fields[itemName.replace(reVectorField, '')] = VectorCol(3, description);
|
||||
console.log(`${d.header} should have 'vector' _item_sub_category.id`);
|
||||
} else {
|
||||
const code = getCode(d, imports, ctx);
|
||||
if (code) {
|
||||
let fieldType = getFieldType(code[0], description, code[1], code[2]);
|
||||
if (fieldType.type === 'str') {
|
||||
if (COMMA_SEPARATED_LIST_FIELDS.includes(d.header)) {
|
||||
fieldType = ListCol('str', ',', description);
|
||||
console.log(`forcing comma separated: ${d.header}`);
|
||||
} else if (SPACE_SEPARATED_LIST_FIELDS.includes(d.header)) {
|
||||
fieldType = ListCol('str', ' ', description);
|
||||
console.log(`forcing space separated: ${d.header}`);
|
||||
} else if (SEMICOLON_SEPARATED_LIST_FIELDS.includes(d.header)) {
|
||||
fieldType = ListCol('str', ';', description);
|
||||
console.log(`forcing space separated: ${d.header}`);
|
||||
}
|
||||
}
|
||||
if (d.header in EXTRA_ENUM_VALUES) {
|
||||
if (fieldType.type === 'enum') {
|
||||
fieldType.values.push(...EXTRA_ENUM_VALUES[d.header]);
|
||||
} else {
|
||||
console.warn(`expected enum: ${d.header}`);
|
||||
}
|
||||
}
|
||||
fields[itemName] = fieldType;
|
||||
} else {
|
||||
fields[itemName] = StrCol(description);
|
||||
// console.log(`could not determine code for '${d.header}'`)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { tables, aliases };
|
||||
}
|
||||
151
src/cli/cifschema/util/generate.ts
Normal file
151
src/cli/cifschema/util/generate.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Database, Filter, Column } from './schema';
|
||||
import { indentString } from '../../../mol-util/string';
|
||||
import { FieldPath } from '../../../mol-io/reader/cif/schema';
|
||||
|
||||
function header(name: string, info: string, moldataImportPath: string) {
|
||||
return `/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated '${name}' schema file. ${info}
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
import { Database, Column } from '${moldataImportPath}/db';
|
||||
|
||||
import Schema = Column.Schema;`;
|
||||
}
|
||||
|
||||
function footer(name: string) {
|
||||
return `
|
||||
export type ${name}_Schema = typeof ${name}_Schema;
|
||||
export interface ${name}_Database extends Database<${name}_Schema> {};`;
|
||||
}
|
||||
|
||||
function getTypeShorthands(schema: Database, fields?: Filter) {
|
||||
const types = new Set<string>();
|
||||
Object.keys(schema.tables).forEach(table => {
|
||||
if (fields && !fields[table]) return;
|
||||
const { columns } = schema.tables[table];
|
||||
Object.keys(columns).forEach(columnName => {
|
||||
if (fields && !fields[table][columnName]) return;
|
||||
types.add(schema.tables[table].columns[columnName].type);
|
||||
});
|
||||
});
|
||||
const shorthands: string[] = [];
|
||||
types.forEach(type => {
|
||||
switch (type) {
|
||||
case 'str': shorthands.push('const str = Schema.str;'); break;
|
||||
case 'int': shorthands.push('const int = Schema.int;'); break;
|
||||
case 'float': shorthands.push('const float = Schema.float;'); break;
|
||||
case 'coord': shorthands.push('const coord = Schema.coord;'); break;
|
||||
case 'enum': shorthands.push('const Aliased = Schema.Aliased;'); break;
|
||||
case 'matrix': shorthands.push('const Matrix = Schema.Matrix;'); break;
|
||||
case 'vector': shorthands.push('const Vector = Schema.Vector;'); break;
|
||||
case 'list': shorthands.push('const List = Schema.List;'); break;
|
||||
}
|
||||
});
|
||||
return shorthands.join('\n');
|
||||
}
|
||||
|
||||
function getTypeDef(c: Column): string {
|
||||
switch (c.type) {
|
||||
case 'str': return 'str';
|
||||
case 'int': return 'int';
|
||||
case 'float': return 'float';
|
||||
case 'coord': return 'coord';
|
||||
case 'enum':
|
||||
return `Aliased<'${c.values.map(v => v.replace(/'/g, '\\\'')).join(`' | '`)}'>(${c.subType})`;
|
||||
case 'matrix':
|
||||
return `Matrix(${c.rows}, ${c.columns})`;
|
||||
case 'vector':
|
||||
return `Vector(${c.length})`;
|
||||
case 'list':
|
||||
if (c.subType === 'int') {
|
||||
return `List('${c.separator}', x => parseInt(x, 10))`;
|
||||
} else if (c.subType === 'float' || c.subType === 'coord') {
|
||||
return `List('${c.separator}', x => parseFloat(x))`;
|
||||
} else {
|
||||
return `List('${c.separator}', x => x)`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const reSafePropertyName = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
|
||||
function safePropertyString(name: string) { return name.match(reSafePropertyName) ? name : `'${name}'`; }
|
||||
|
||||
function doc(description: string, spacesCount: number) {
|
||||
const spaces = ' '.repeat(spacesCount);
|
||||
return [
|
||||
`${spaces}/**`,
|
||||
`${indentString(description, 1, `${spaces} * `)}`.replace(/ +\n/g, '\n'),
|
||||
`${spaces} */`
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
export function generate(name: string, info: string, schema: Database, fields: Filter | undefined, moldataImportPath: string, addAliases: boolean) {
|
||||
const codeLines: string[] = [];
|
||||
|
||||
if (fields) {
|
||||
Object.keys(fields).forEach(table => {
|
||||
if (table in schema.tables) {
|
||||
const schemaTable = schema.tables[table];
|
||||
Object.keys(fields[table]).forEach(column => {
|
||||
if (!(column in schemaTable.columns)) {
|
||||
console.log(`filter field '${table}.${column}' not found in schema`);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(`filter category '${table}' not found in schema`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
codeLines.push(`export const ${name}_Schema = {`);
|
||||
Object.keys(schema.tables).forEach(table => {
|
||||
if (fields && !fields[table]) return;
|
||||
const { description, columns } = schema.tables[table];
|
||||
if (description) codeLines.push(doc(description, 4));
|
||||
codeLines.push(` ${safePropertyString(table)}: {`);
|
||||
Object.keys(columns).forEach(columnName => {
|
||||
if (fields && !fields[table][columnName]) return;
|
||||
const c = columns[columnName];
|
||||
const typeDef = getTypeDef(c);
|
||||
if (c.description) codeLines.push(doc(c.description, 8));
|
||||
codeLines.push(` ${safePropertyString(columnName)}: ${typeDef},`);
|
||||
});
|
||||
codeLines.push(' },');
|
||||
});
|
||||
codeLines.push('};');
|
||||
|
||||
if (addAliases) {
|
||||
codeLines.push('');
|
||||
codeLines.push(`export const ${name}_Aliases = {`);
|
||||
Object.keys(schema.aliases).forEach(path => {
|
||||
const [table, columnName] = path.split('.');
|
||||
if (fields && !fields[table]) return;
|
||||
if (fields && !fields[table][columnName]) return;
|
||||
|
||||
const filteredAliases = new Set<string>();
|
||||
schema.aliases[path].forEach(p => {
|
||||
if (!FieldPath.equal(p, path)) filteredAliases.add(FieldPath.canonical(p));
|
||||
});
|
||||
|
||||
if (filteredAliases.size === 0) return;
|
||||
codeLines.push(` ${safePropertyString(path)}: [`);
|
||||
filteredAliases.forEach(alias => {
|
||||
codeLines.push(` '${alias}',`);
|
||||
});
|
||||
codeLines.push(' ],');
|
||||
});
|
||||
codeLines.push('};');
|
||||
}
|
||||
|
||||
return `${header(name, info, moldataImportPath)}\n\n${getTypeShorthands(schema, fields)}\n\n${codeLines.join('\n')}\n${footer(name)}`;
|
||||
}
|
||||
20
src/cli/cifschema/util/helper.ts
Normal file
20
src/cli/cifschema/util/helper.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
export type Import = { save?: string, file?: string }
|
||||
|
||||
export function parseImportGet(s: string): Import[] {
|
||||
// [{'save':hi_ang_Fox_coeffs 'file':templ_attr.cif} {'save':hi_ang_Fox_c0 'file':templ_enum.cif}]
|
||||
// [{"file":'templ_enum.cif' "save":'H_M_ref'}]
|
||||
return s.trim().substring(2, s.length - 2).split(/}[ \n\t]*{/g).map(s => {
|
||||
const save = s.match(/('save'|"save"):([^ \t\n{}]+)/);
|
||||
const file = s.match(/('file'|"file"):([^ \t\n{}]+)/);
|
||||
return {
|
||||
save: save ? save[0].substr(7).replace(/['"]/g, '') : undefined,
|
||||
file: file ? file[0].substr(7).replace(/['"]/g, '') : undefined
|
||||
};
|
||||
});
|
||||
}
|
||||
77
src/cli/cifschema/util/schema.ts
Normal file
77
src/cli/cifschema/util/schema.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
export interface Database {
|
||||
tables: { [ tableName: string ]: Table }
|
||||
aliases: { [ path: string ]: string[] }
|
||||
}
|
||||
export interface Table {
|
||||
description: string
|
||||
key: Set<string>
|
||||
columns: { [ columnName: string ]: Column }
|
||||
}
|
||||
export type Column = IntCol | StrCol | FloatCol | CoordCol | EnumCol | VectorCol | MatrixCol | ListCol
|
||||
|
||||
type BaseCol = { description: string }
|
||||
|
||||
export type IntCol = { type: 'int' } & BaseCol
|
||||
export function IntCol(description: string): IntCol { return { type: 'int', description }; }
|
||||
|
||||
export type StrCol = { type: 'str' } & BaseCol
|
||||
export function StrCol(description: string): StrCol { return { type: 'str', description }; }
|
||||
|
||||
export type FloatCol = { type: 'float' } & BaseCol
|
||||
export function FloatCol(description: string): FloatCol { return { type: 'float', description }; }
|
||||
|
||||
export type CoordCol = { type: 'coord' } & BaseCol
|
||||
export function CoordCol(description: string): CoordCol { return { type: 'coord', description }; }
|
||||
|
||||
export type EnumCol = { type: 'enum', subType: 'int' | 'str', values: string[] } & BaseCol
|
||||
export function EnumCol(values: string[], subType: 'int' | 'str', description: string): EnumCol {
|
||||
return { type: 'enum', description, values, subType };
|
||||
}
|
||||
|
||||
export type VectorCol = { type: 'vector', length: number } & BaseCol
|
||||
export function VectorCol(length: number, description: string): VectorCol {
|
||||
return { type: 'vector', description, length };
|
||||
}
|
||||
|
||||
export type MatrixCol = { type: 'matrix', rows: number, columns: number } & BaseCol
|
||||
export function MatrixCol(columns: number, rows: number, description: string): MatrixCol {
|
||||
return { type: 'matrix', description, columns, rows };
|
||||
}
|
||||
|
||||
export type ListCol = { type: 'list', subType: 'int' | 'str' | 'float' | 'coord', separator: string } & BaseCol
|
||||
export function ListCol(subType: 'int' | 'str' | 'float' | 'coord', separator: string, description: string): ListCol {
|
||||
return { type: 'list', description, separator, subType };
|
||||
}
|
||||
|
||||
export type Filter = { [ table: string ]: { [ column: string ]: true } }
|
||||
|
||||
export function mergeFilters(...filters: Filter[]) {
|
||||
const n = filters.length;
|
||||
const mergedFilter: Filter = {};
|
||||
const fields: Map<string, number> = new Map();
|
||||
filters.forEach(filter => {
|
||||
Object.keys(filter).forEach(category => {
|
||||
Object.keys(filter[category]).forEach(field => {
|
||||
const key = `${category}.${field}`;
|
||||
const value = fields.get(key) || 0;
|
||||
fields.set(key, value + 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
fields.forEach((v, k) => {
|
||||
if (v !== n) return;
|
||||
const [categoryName, fieldName] = k.split('.');
|
||||
if (categoryName in mergedFilter) {
|
||||
mergedFilter[categoryName][fieldName] = true;
|
||||
} else {
|
||||
mergedFilter[categoryName] = { fieldName: true };
|
||||
}
|
||||
});
|
||||
return mergedFilter;
|
||||
}
|
||||
93
src/cli/lipid-params/index.ts
Normal file
93
src/cli/lipid-params/index.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import fetch from 'node-fetch';
|
||||
import { UniqueArray } from '../../mol-data/generic';
|
||||
|
||||
const LIPIDS_DIR = path.resolve(__dirname, '../../../../build/lipids/');
|
||||
|
||||
const MARTINI_LIPIDS_PATH = path.resolve(LIPIDS_DIR, 'martini_lipids.itp');
|
||||
const MARTINI_LIPIDS_URL = 'http://www.cgmartini.nl/images/parameters/lipids/Collections/martini_v2.0_lipids_all_201506.itp';
|
||||
|
||||
async function ensureAvailable(path: string, url: string) {
|
||||
if (FORCE_DOWNLOAD || !fs.existsSync(path)) {
|
||||
const name = url.substr(url.lastIndexOf('/') + 1);
|
||||
console.log(`downloading ${name}...`);
|
||||
const data = await fetch(url);
|
||||
if (!fs.existsSync(LIPIDS_DIR)) {
|
||||
fs.mkdirSync(LIPIDS_DIR);
|
||||
}
|
||||
fs.writeFileSync(path, await data.text());
|
||||
console.log(`done downloading ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureLipidsAvailable() { await ensureAvailable(MARTINI_LIPIDS_PATH, MARTINI_LIPIDS_URL); }
|
||||
|
||||
const extraLipids = ['DMPC'];
|
||||
|
||||
async function run(out: string) {
|
||||
await ensureLipidsAvailable();
|
||||
const lipidsItpStr = fs.readFileSync(MARTINI_LIPIDS_PATH, 'utf8');
|
||||
|
||||
const lipids = UniqueArray.create<string>();
|
||||
const reLipid = /\[moleculetype\]\n; molname nrexcl\n +([a-zA-Z]{3,5})/g;
|
||||
let m: RegExpExecArray | null;
|
||||
|
||||
while ((m = reLipid.exec(lipidsItpStr)) !== null) {
|
||||
const v = m[0].substr(m[0].lastIndexOf(' ') + 1);
|
||||
UniqueArray.add(lipids, v, v);
|
||||
}
|
||||
|
||||
for (const v of extraLipids) {
|
||||
UniqueArray.add(lipids, v, v);
|
||||
}
|
||||
|
||||
const lipidNames = JSON.stringify(lipids.array);
|
||||
|
||||
if (out) {
|
||||
const output = `/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated lipid params file. Names extracted from Martini FF lipids itp.
|
||||
*
|
||||
* @author molstar/lipid-params cli
|
||||
*/
|
||||
|
||||
export const LipidNames = new Set(${lipidNames.replace(/"/g, "'").replace(/,/g, ', ')});
|
||||
`;
|
||||
fs.writeFileSync(out, output);
|
||||
} else {
|
||||
console.log(lipidNames);
|
||||
}
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Create lipid params (from martini lipids itp)'
|
||||
});
|
||||
parser.add_argument('--out', '-o', {
|
||||
help: 'Generated lipid params output path, if not given printed to stdout'
|
||||
});
|
||||
parser.add_argument('--forceDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of martini lipids itp'
|
||||
});
|
||||
interface Args {
|
||||
out: string
|
||||
forceDownload: boolean
|
||||
}
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
const FORCE_DOWNLOAD = args.forceDownload;
|
||||
|
||||
run(args.out || '').catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as _ from '../../mol-plugin/state/transforms'
|
||||
import * as _ from '../../mol-plugin-state/transforms';
|
||||
import { StateTransformer, StateObject } from '../../mol-state';
|
||||
import { StringBuilder } from '../../mol-util';
|
||||
import * as fs from 'fs';
|
||||
@@ -13,11 +14,10 @@ import { PluginContext } from '../../mol-plugin/context';
|
||||
import { ParamDefinition } from '../../mol-util/param-definition';
|
||||
|
||||
// force the transform to be evaluated
|
||||
_.StateTransforms.Data.Download.id
|
||||
_.StateTransforms.Data.Download.id;
|
||||
|
||||
// Empty plugin context
|
||||
const ctx = new PluginContext({
|
||||
actions: [],
|
||||
behaviors: []
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ function writeTransformer(t: StateTransformer) {
|
||||
StringBuilder.write(builder, `## <a name="${t.id.replace('.', '-')}"></a>${t.id} :: ${typeToString(t.definition.from)} -> ${typeToString(t.definition.to)}`);
|
||||
StringBuilder.newline(builder);
|
||||
if (t.definition.display.description) {
|
||||
StringBuilder.write(builder, `*${t.definition.display.description}*`)
|
||||
StringBuilder.write(builder, `*${t.definition.display.description}*`);
|
||||
StringBuilder.newline(builder);
|
||||
}
|
||||
StringBuilder.newline(builder);
|
||||
@@ -48,7 +48,7 @@ function writeTransformer(t: StateTransformer) {
|
||||
StringBuilder.write(builder, `\`\`\`js\n${JSON.stringify(ParamDefinition.getDefaultValues(params), null, 2)}\n\`\`\``);
|
||||
StringBuilder.newline(builder);
|
||||
}
|
||||
StringBuilder.write(builder, '----------------------------')
|
||||
StringBuilder.write(builder, '----------------------------');
|
||||
StringBuilder.newline(builder);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ transformers.forEach(t => {
|
||||
StringBuilder.newline(builder);
|
||||
});
|
||||
StringBuilder.newline(builder);
|
||||
StringBuilder.write(builder, '----------------------------')
|
||||
StringBuilder.write(builder, '----------------------------');
|
||||
StringBuilder.newline(builder);
|
||||
transformers.forEach(t => writeTransformer(t));
|
||||
|
||||
@@ -19,10 +19,15 @@ function paramInfo(param: PD.Any, offset: number): string {
|
||||
case 'conditioned': return getParams(param.conditionParams, offset);
|
||||
case 'multi-select': return `Array of ${oToS(param.options)}`;
|
||||
case 'color': return 'Color as 0xrrggbb';
|
||||
case 'color-scale': return `One of ${oToS(param.options)}`;
|
||||
case 'color-list': return `A list of colors as 0xrrggbb`;
|
||||
case 'vec3': return `3D vector [x, y, z]`;
|
||||
case 'mat4': return `4x4 transformation matrix`;
|
||||
case 'url': return `URL couple with unique identifier`;
|
||||
case 'file': return `JavaScript File Handle`;
|
||||
case 'file-list': return `JavaScript FileList Handle`;
|
||||
case 'select': return `One of ${oToS(param.options)}`;
|
||||
case 'value-ref': return `Reference to a runtime defined value.`;
|
||||
case 'data-ref': return `Reference to a computed data value.`;
|
||||
case 'text': return 'String';
|
||||
case 'interval': return `Interval [min, max]`;
|
||||
case 'group': return `Object with:\n${getParams(param.params, offset + 2)}`;
|
||||
@@ -30,7 +35,7 @@ function paramInfo(param: PD.Any, offset: number): string {
|
||||
case 'line-graph': return `A list of 2d vectors [xi, yi][]`;
|
||||
case 'object-list': return `Array of\n${paramInfo(PD.Group(param.element), offset + 2)}`;
|
||||
// TODO: support more languages
|
||||
case 'script-expression': return `An expression in the specified language { language: 'mol-script', expressiong: string }`;
|
||||
case 'script': return `An expression in the specified language { language: 'mol-script', expressiong: string }`;
|
||||
default:
|
||||
const _: never = param;
|
||||
console.warn(`${_} has no associated UI component`);
|
||||
@@ -38,7 +43,7 @@ function paramInfo(param: PD.Any, offset: number): string {
|
||||
}
|
||||
}
|
||||
|
||||
function oToS(options: [string, string][]) {
|
||||
function oToS(options: readonly (readonly [string, string] | readonly [string, string, string | undefined])[]) {
|
||||
return options.map(o => `'${o[0]}'`).join(', ');
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as util from 'util'
|
||||
import * as fs from 'fs'
|
||||
import fetch from 'node-fetch'
|
||||
import * as util from 'util';
|
||||
import * as fs from 'fs';
|
||||
import fetch from 'node-fetch';
|
||||
require('util.promisify').shim();
|
||||
|
||||
import { CIF } from '../../mol-io/reader/cif'
|
||||
import { Progress } from '../../mol-task'
|
||||
import { CIF } from '../../mol-io/reader/cif';
|
||||
import { Progress } from '../../mol-task';
|
||||
|
||||
const readFileAsync = util.promisify(fs.readFile);
|
||||
|
||||
async function readFile(path: string) {
|
||||
if (path.match(/\.bcif$/)) {
|
||||
const input = await readFileAsync(path)
|
||||
const input = await readFileAsync(path);
|
||||
const data = new Uint8Array(input.byteLength);
|
||||
for (let i = 0; i < input.byteLength; i++) data[i] = input[i];
|
||||
return data;
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
@@ -5,16 +6,20 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse'
|
||||
import * as argparse from 'argparse';
|
||||
require('util.promisify').shim();
|
||||
|
||||
import { CifFrame } from '../../mol-io/reader/cif'
|
||||
import { Model, Structure, StructureElement, Unit, StructureProperties, UnitRing } from '../../mol-model/structure'
|
||||
import { CifFrame } from '../../mol-io/reader/cif';
|
||||
import { Model, Structure, StructureElement, Unit, StructureProperties, UnitRing, Trajectory } from '../../mol-model/structure';
|
||||
// import { Run, Progress } from '../../mol-task'
|
||||
import { OrderedSet } from '../../mol-data/int';
|
||||
import { openCif, downloadCif } from './helpers';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { trajectoryFromMmCIF } from '../../mol-model-formats/structure/mmcif';
|
||||
import { Sequence } from '../../mol-model/sequence';
|
||||
import { ModelSecondaryStructure } from '../../mol-model-formats/structure/property/secondary-structure';
|
||||
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
|
||||
import { Task } from '../../mol-task';
|
||||
|
||||
|
||||
async function downloadFromPdb(pdb: string) {
|
||||
@@ -29,32 +34,36 @@ export async function readCifFile(path: string) {
|
||||
}
|
||||
|
||||
export function atomLabel(model: Model, aI: number) {
|
||||
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy
|
||||
const { label_atom_id } = atoms
|
||||
const { label_comp_id, label_seq_id } = residues
|
||||
const { label_asym_id } = chains
|
||||
const rI = residueAtomSegments.index[aI]
|
||||
const cI = chainAtomSegments.index[aI]
|
||||
return `${label_asym_id.value(cI)} ${label_comp_id.value(rI)} ${label_seq_id.value(rI)} ${label_atom_id.value(aI)}`
|
||||
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy;
|
||||
const { label_atom_id, label_comp_id } = atoms;
|
||||
const { label_seq_id } = residues;
|
||||
const { label_asym_id } = chains;
|
||||
const rI = residueAtomSegments.index[aI];
|
||||
const cI = chainAtomSegments.index[aI];
|
||||
return `${label_asym_id.value(cI)} ${label_comp_id.value(aI)} ${label_seq_id.value(rI)} ${label_atom_id.value(aI)}`;
|
||||
}
|
||||
|
||||
export function residueLabel(model: Model, rI: number) {
|
||||
const { residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy
|
||||
const { label_comp_id, label_seq_id } = residues
|
||||
const { label_asym_id } = chains
|
||||
const cI = chainAtomSegments.index[residueAtomSegments.offsets[rI]]
|
||||
return `${label_asym_id.value(cI)} ${label_comp_id.value(rI)} ${label_seq_id.value(rI)}`
|
||||
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy;
|
||||
const { label_comp_id } = atoms;
|
||||
const { label_seq_id } = residues;
|
||||
const { label_asym_id } = chains;
|
||||
const aI = residueAtomSegments.offsets[rI];
|
||||
const cI = chainAtomSegments.index[aI];
|
||||
return `${label_asym_id.value(cI)} ${label_comp_id.value(aI)} ${label_seq_id.value(rI)}`;
|
||||
}
|
||||
|
||||
export function printSecStructure(model: Model) {
|
||||
console.log('\nSecondary Structure\n=============');
|
||||
const { residues } = model.atomicHierarchy;
|
||||
const { key, elements } = model.properties.secondaryStructure;
|
||||
const secondaryStructure = ModelSecondaryStructure.Provider.get(model);
|
||||
if (!secondaryStructure) return;
|
||||
|
||||
const { key, elements } = secondaryStructure;
|
||||
const count = residues._rowCount;
|
||||
let rI = 0;
|
||||
while (rI < count) {
|
||||
let start = rI;
|
||||
const start = rI;
|
||||
while (rI < count && key[start] === key[rI]) rI++;
|
||||
rI--;
|
||||
|
||||
@@ -64,14 +73,14 @@ export function printSecStructure(model: Model) {
|
||||
}
|
||||
}
|
||||
|
||||
export function printLinks(structure: Structure, showIntra: boolean, showInter: boolean) {
|
||||
export function printBonds(structure: Structure, showIntra: boolean, showInter: boolean) {
|
||||
if (showIntra) {
|
||||
console.log('\nIntra Unit Links\n=============');
|
||||
console.log('\nIntra Unit Bonds\n=============');
|
||||
for (const unit of structure.units) {
|
||||
if (!Unit.isAtomic(unit)) continue;
|
||||
|
||||
const elements = unit.elements;
|
||||
const { a, b, edgeCount } = unit.links;
|
||||
const { a, b, edgeCount } = unit.bonds;
|
||||
const { model } = unit;
|
||||
|
||||
if (!edgeCount) continue;
|
||||
@@ -85,20 +94,22 @@ export function printLinks(structure: Structure, showIntra: boolean, showInter:
|
||||
}
|
||||
|
||||
if (showInter) {
|
||||
console.log('\nInter Unit Links\n=============');
|
||||
const links = structure.links;
|
||||
console.log('\nInter Unit Bonds\n=============');
|
||||
const bonds = structure.interUnitBonds;
|
||||
for (const unit of structure.units) {
|
||||
if (!Unit.isAtomic(unit)) continue;
|
||||
|
||||
for (const pairLinks of links.getLinkedUnits(unit)) {
|
||||
if (!pairLinks.areUnitsOrdered || pairLinks.bondCount === 0) continue;
|
||||
for (const pairBonds of bonds.getConnectedUnits(unit.id)) {
|
||||
if (!pairBonds.areUnitsOrdered || pairBonds.edgeCount === 0) continue;
|
||||
|
||||
const { unitA, unitB } = pairLinks;
|
||||
console.log(`${pairLinks.unitA.id} - ${pairLinks.unitB.id}: ${pairLinks.bondCount} bond(s)`);
|
||||
const { unitA, unitB, edgeCount } = pairBonds;
|
||||
const uA = structure.unitMap.get(unitA);
|
||||
const uB = structure.unitMap.get(unitB);
|
||||
console.log(`${unitA} - ${unitB}: ${edgeCount} bond(s)`);
|
||||
|
||||
for (const aI of pairLinks.linkedElementIndices) {
|
||||
for (const link of pairLinks.getBonds(aI)) {
|
||||
console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[link.indexB])}`);
|
||||
for (const aI of pairBonds.connectedIndices) {
|
||||
for (const bond of pairBonds.getEdges(aI)) {
|
||||
console.log(`${atomLabel(uA.model, uA.elements[aI])} -- ${atomLabel(uB.model, uB.elements[bond.indexB])}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,21 +121,10 @@ export function printSequence(model: Model) {
|
||||
console.log('\nSequence\n=============');
|
||||
const { byEntityKey } = model.sequence;
|
||||
for (const key of Object.keys(byEntityKey)) {
|
||||
const seq = byEntityKey[+key];
|
||||
console.log(`${seq.entityId} (${seq.sequence.kind} ${seq.num.value(0)} (offset ${seq.sequence.offset}), ${seq.num.value(seq.num.rowCount - 1)}) (${seq.compId.value(0)}, ${seq.compId.value(seq.compId.rowCount - 1)})`);
|
||||
console.log(`${seq.sequence.sequence}`);
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
|
||||
export function printModRes(model: Model) {
|
||||
console.log('\nModified Residues\n=============');
|
||||
const map = model.properties.modifiedResidues.parentId;
|
||||
const { label_comp_id, _rowCount } = model.atomicHierarchy.residues;
|
||||
for (let i = 0; i < _rowCount; i++) {
|
||||
const comp_id = label_comp_id.value(i);
|
||||
if (!map.has(comp_id)) continue;
|
||||
console.log(`[${i}] ${map.get(comp_id)} -> ${comp_id}`);
|
||||
const { sequence, entityId } = byEntityKey[+key];
|
||||
const { seqId, compId } = sequence;
|
||||
console.log(`${entityId} (${sequence.kind} ${seqId.value(0)}, ${seqId.value(seqId.rowCount - 1)}) (${compId.value(0)}, ${compId.value(compId.rowCount - 1)})`);
|
||||
console.log(`${Sequence.getSequenceString(sequence)}`);
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
@@ -138,7 +138,7 @@ export function printRings(structure: Structure) {
|
||||
for (let i = 0, _i = Math.min(5, all.length); i < _i; i++) {
|
||||
fps[fps.length] = UnitRing.fingerprint(unit, all[i]);
|
||||
}
|
||||
if (all.length > 5) fps.push('...')
|
||||
if (all.length > 5) fps.push('...');
|
||||
console.log(`Unit ${unit.id}, ${all.length} ring(s), ${byFingerprint.size} different fingerprint(s).\n ${fps.join(', ')}`);
|
||||
}
|
||||
console.log();
|
||||
@@ -146,7 +146,7 @@ export function printRings(structure: Structure) {
|
||||
|
||||
export function printUnits(structure: Structure) {
|
||||
console.log('\nUnits\n=============');
|
||||
const l = StructureElement.create();
|
||||
const l = StructureElement.Location.create(structure);
|
||||
|
||||
for (const unit of structure.units) {
|
||||
l.unit = unit;
|
||||
@@ -159,14 +159,14 @@ export function printUnits(structure: Structure) {
|
||||
console.log(`Coarse unit ${unit.id} ${unit.conformation.operator.name} (${Unit.isSpheres(l.unit) ? 'spheres' : 'gaussians'}): ${size} elements.`);
|
||||
|
||||
const props = StructureProperties.coarse;
|
||||
const seq = l.unit.model.sequence;
|
||||
const modelSeq = l.unit.model.sequence;
|
||||
|
||||
for (let j = 0, _j = Math.min(size, 3); j < _j; j++) {
|
||||
l.element = OrderedSet.getAt(elements, j);
|
||||
|
||||
const residues: string[] = [];
|
||||
const start = props.seq_id_begin(l), end = props.seq_id_end(l);
|
||||
const compId = seq.byEntityKey[props.entityKey(l)].compId.value;
|
||||
const compId = modelSeq.byEntityKey[props.entityKey(l)].sequence.compId.value;
|
||||
for (let e = start; e <= end; e++) residues.push(compId(e));
|
||||
console.log(`${props.asym_id(l)}:${start}-${end} (${residues.join('-')}) ${props.asym_id(l)} [${props.x(l).toFixed(2)}, ${props.y(l).toFixed(2)}, ${props.z(l).toFixed(2)}]`);
|
||||
}
|
||||
@@ -177,7 +177,8 @@ export function printUnits(structure: Structure) {
|
||||
|
||||
export function printSymmetryInfo(model: Model) {
|
||||
console.log('\nSymmetry Info\n=============');
|
||||
const { symmetry } = model;
|
||||
const symmetry = ModelSymmetry.Provider.get(model);
|
||||
if (!symmetry) return;
|
||||
const { size, anglesInRadians } = symmetry.spacegroup.cell;
|
||||
console.log(`Spacegroup: ${symmetry.spacegroup.name} size: ${Vec3.toString(size)} angles: ${Vec3.toString(anglesInRadians)}`);
|
||||
console.log(`Assembly names: ${symmetry.assemblies.map(a => a.id).join(', ')}`);
|
||||
@@ -185,10 +186,11 @@ export function printSymmetryInfo(model: Model) {
|
||||
console.log(`NCS operators: ${symmetry.ncsOperators && symmetry.ncsOperators.map(a => a.name).join(', ')}`);
|
||||
}
|
||||
|
||||
export function printModelStats(models: ReadonlyArray<Model>) {
|
||||
export async function printModelStats(models: Trajectory) {
|
||||
console.log('\nModels\n=============');
|
||||
|
||||
for (const m of models) {
|
||||
for (let i = 0; i < models.frameCount; i++) {
|
||||
const m = await Task.resolveInContext(models.getFrameAtIndex(i));
|
||||
if (m.coarseHierarchy.isDefined) {
|
||||
console.log(`${m.label} ${m.modelNum}: ${m.atomicHierarchy.atoms._rowCount} atom(s), ${m.coarseHierarchy.spheres.count} sphere(s), ${m.coarseHierarchy.gaussians.count} gaussian(s)`);
|
||||
} else {
|
||||
@@ -200,7 +202,7 @@ export function printModelStats(models: ReadonlyArray<Model>) {
|
||||
|
||||
export async function getModelsAndStructure(frame: CifFrame) {
|
||||
const models = await trajectoryFromMmCIF(frame).run();
|
||||
const structure = Structure.ofModel(models[0]);
|
||||
const structure = Structure.ofModel(models.representative);
|
||||
return { models, structure };
|
||||
}
|
||||
|
||||
@@ -208,18 +210,17 @@ async function run(frame: CifFrame, args: Args) {
|
||||
const { models, structure } = await getModelsAndStructure(frame);
|
||||
|
||||
if (args.models) printModelStats(models);
|
||||
if (args.seq) printSequence(models[0]);
|
||||
if (args.seq) printSequence(models.representative);
|
||||
if (args.units) printUnits(structure);
|
||||
if (args.sym) printSymmetryInfo(models[0]);
|
||||
if (args.sym) printSymmetryInfo(models.representative);
|
||||
if (args.rings) printRings(structure);
|
||||
if (args.intraLinks) printLinks(structure, true, false);
|
||||
if (args.interLinks) printLinks(structure, false, true);
|
||||
if (args.mod) printModRes(models[0]);
|
||||
if (args.sec) printSecStructure(models[0]);
|
||||
if (args.intraBonds) printBonds(structure, true, false);
|
||||
if (args.interBonds) printBonds(structure, false, true);
|
||||
if (args.sec) printSecStructure(models.representative);
|
||||
}
|
||||
|
||||
async function runDL(pdb: string, args: Args) {
|
||||
const mmcif = await downloadFromPdb(pdb)
|
||||
const mmcif = await downloadFromPdb(pdb);
|
||||
run(mmcif, args);
|
||||
}
|
||||
|
||||
@@ -229,21 +230,21 @@ async function runFile(filename: string, args: Args) {
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Print info about a structure, mainly to test and showcase the mol-model module'
|
||||
});
|
||||
parser.addArgument(['--download', '-d'], { help: 'Pdb entry id' });
|
||||
parser.addArgument(['--file', '-f'], { help: 'filename' });
|
||||
parser.add_argument('--download', '-d', { help: 'Pdb entry id' });
|
||||
parser.add_argument('--file', '-f', { help: 'filename' });
|
||||
|
||||
parser.addArgument(['--models'], { help: 'print models info', action: 'storeTrue' });
|
||||
parser.addArgument(['--seq'], { help: 'print sequence', action: 'storeTrue' });
|
||||
parser.addArgument(['--units'], { help: 'print units', action: 'storeTrue' });
|
||||
parser.addArgument(['--sym'], { help: 'print symmetry', action: 'storeTrue' });
|
||||
parser.addArgument(['--rings'], { help: 'print rings', action: 'storeTrue' });
|
||||
parser.addArgument(['--intraLinks'], { help: 'print intra unit links', action: 'storeTrue' });
|
||||
parser.addArgument(['--interLinks'], { help: 'print inter unit links', action: 'storeTrue' });
|
||||
parser.addArgument(['--mod'], { help: 'print modified residues', action: 'storeTrue' });
|
||||
parser.addArgument(['--sec'], { help: 'print secoundary structure', action: 'storeTrue' });
|
||||
parser.add_argument('--models', { help: 'print models info', action: 'store_true' });
|
||||
parser.add_argument('--seq', { help: 'print sequence', action: 'store_true' });
|
||||
parser.add_argument('--units', { help: 'print units', action: 'store_true' });
|
||||
parser.add_argument('--sym', { help: 'print symmetry', action: 'store_true' });
|
||||
parser.add_argument('--rings', { help: 'print rings', action: 'store_true' });
|
||||
parser.add_argument('--intraBonds', { help: 'print intra unit bonds', action: 'store_true' });
|
||||
parser.add_argument('--interBonds', { help: 'print inter unit bonds', action: 'store_true' });
|
||||
parser.add_argument('--mod', { help: 'print modified residues', action: 'store_true' });
|
||||
parser.add_argument('--sec', { help: 'print secoundary structure', action: 'store_true' });
|
||||
interface Args {
|
||||
download?: string,
|
||||
file?: string,
|
||||
@@ -254,12 +255,12 @@ interface Args {
|
||||
units?: boolean,
|
||||
sym?: boolean,
|
||||
rings?: boolean,
|
||||
intraLinks?: boolean,
|
||||
interLinks?: boolean,
|
||||
intraBonds?: boolean,
|
||||
interBonds?: boolean,
|
||||
mod?: boolean,
|
||||
sec?: boolean,
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
if (args.download) runDL(args.download, args)
|
||||
else if (args.file) runFile(args.file, args)
|
||||
if (args.download) runDL(args.download, args);
|
||||
else if (args.file) runFile(args.file, args);
|
||||
@@ -1,46 +1,44 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as fs from 'fs'
|
||||
import * as argparse from 'argparse'
|
||||
import * as util from 'util'
|
||||
import * as fs from 'fs';
|
||||
import * as argparse from 'argparse';
|
||||
import * as util from 'util';
|
||||
|
||||
import { VolumeData, VolumeIsoValue } from '../../mol-model/volume'
|
||||
import { downloadCif } from './helpers'
|
||||
import { CIF } from '../../mol-io/reader/cif'
|
||||
import { DensityServer_Data_Database } from '../../mol-io/reader/cif/schema/density-server';
|
||||
import { Volume } from '../../mol-model/volume';
|
||||
import { downloadCif } from './helpers';
|
||||
import { CIF } from '../../mol-io/reader/cif';
|
||||
import { Table } from '../../mol-data/db';
|
||||
import { StringBuilder } from '../../mol-util';
|
||||
import { Task } from '../../mol-task';
|
||||
import { createVolumeIsosurfaceMesh } from '../../mol-repr/volume/isosurface';
|
||||
import { createEmptyTheme } from '../../mol-theme/theme';
|
||||
import { volumeFromDensityServerData } from '../../mol-model-formats/volume/density-server';
|
||||
import { Theme } from '../../mol-theme/theme';
|
||||
import { volumeFromDensityServerData, DscifFormat } from '../../mol-model-formats/volume/density-server';
|
||||
|
||||
require('util.promisify').shim();
|
||||
const writeFileAsync = util.promisify(fs.writeFile);
|
||||
|
||||
type Volume = { source: DensityServer_Data_Database, volume: VolumeData }
|
||||
|
||||
async function getVolume(url: string): Promise<Volume> {
|
||||
const cif = await downloadCif(url, true);
|
||||
const data = CIF.schema.densityServer(cif.blocks[1]);
|
||||
return { source: data, volume: await volumeFromDensityServerData(data).run() };
|
||||
return await volumeFromDensityServerData(data).run();
|
||||
}
|
||||
|
||||
function print(data: Volume) {
|
||||
const { volume_data_3d_info } = data.source;
|
||||
function print(volume: Volume) {
|
||||
if (!DscifFormat.is(volume.sourceData)) return;
|
||||
const { volume_data_3d_info } = volume.sourceData.data;
|
||||
const row = Table.getRow(volume_data_3d_info, 0);
|
||||
console.log(row);
|
||||
console.log(data.volume.cell);
|
||||
console.log(data.volume.dataStats);
|
||||
console.log(data.volume.fractionalBox);
|
||||
console.log(volume.grid.transform);
|
||||
console.log(volume.grid.stats);
|
||||
}
|
||||
|
||||
async function doMesh(data: Volume, filename: string) {
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, data.volume, createEmptyTheme(), { isoValue: VolumeIsoValue.absolute(1.5) } )).run();
|
||||
async function doMesh(volume: Volume, filename: string) {
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) })).run();
|
||||
console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount });
|
||||
|
||||
// Export the mesh in OBJ format.
|
||||
@@ -77,13 +75,13 @@ async function run(url: string, meshFilename: string) {
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
description: 'Info about VolumeData from mol-model module'
|
||||
add_help: true,
|
||||
description: 'Info about VolumeData from mol-model module'
|
||||
});
|
||||
parser.addArgument([ '--emdb', '-e' ], {
|
||||
parser.add_argument('--emdb', '-e', {
|
||||
help: 'EMDB id, for example 8116',
|
||||
});
|
||||
parser.addArgument([ '--mesh' ], {
|
||||
parser.add_argument('--mesh', {
|
||||
help: 'Mesh filename',
|
||||
required: true
|
||||
});
|
||||
@@ -91,6 +89,6 @@ interface Args {
|
||||
emdb?: string,
|
||||
mesh: string
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
run(`https://ds.litemol.org/em/emd-${args.emdb}/cell?detail=4`, args.mesh);
|
||||
24
src/examples/alpha-orbitals/controls.tsx
Normal file
24
src/examples/alpha-orbitals/controls.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { AlphaOrbitalsExample } from '.';
|
||||
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
|
||||
import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior';
|
||||
import { PluginContextContainer } from '../../mol-plugin-ui/plugin';
|
||||
|
||||
export function mountControls(orbitals: AlphaOrbitalsExample, parent: Element) {
|
||||
ReactDOM.render(<PluginContextContainer plugin={orbitals.plugin}>
|
||||
<Controls orbitals={orbitals} />
|
||||
</PluginContextContainer>, parent);
|
||||
}
|
||||
|
||||
function Controls({ orbitals }: { orbitals: AlphaOrbitalsExample }) {
|
||||
const params = useBehavior(orbitals.params);
|
||||
const values = useBehavior(orbitals.state);
|
||||
|
||||
return <ParameterControls params={params as any} values={values} onChangeValues={(vs: any) => orbitals.state.next(vs)} />;
|
||||
}
|
||||
60420
src/examples/alpha-orbitals/example-data.ts
Normal file
60420
src/examples/alpha-orbitals/example-data.ts
Normal file
File diff suppressed because it is too large
Load Diff
61
src/examples/alpha-orbitals/index.html
Normal file
61
src/examples/alpha-orbitals/index.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<title>Mol* Alpha Orbitals Example</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#app {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
#controls {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 8px;
|
||||
width: 300px;
|
||||
}
|
||||
#sponsor {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
bottom: 8px;
|
||||
font-family: "Helvetica Neue", "Segoe UI", Helvetica, "Source Sans Pro", Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
#sponsor svg {
|
||||
fill: #128EA4;
|
||||
width: 100px;
|
||||
}
|
||||
#sponsor a {
|
||||
text-decoration: none;
|
||||
color: #128EA4;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
<script type="text/javascript" src="./index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id='controls'></div>
|
||||
<div id='sponsor'>
|
||||
<a href='https://www.entos.ai/envision' target="_blank" rel="noopener">
|
||||
<svg class="makeStyles-root-46" viewBox="0 0 190 36" xmlns="http://www.w3.org/2000/svg"><path d="M32.2591 28.6707C32.2591 32.3914 29.2421 35.407 25.5214 35.407C22.0752 35.407 19.2338 32.8206 18.8325 29.4831V29.4775C18.8143 29.3312 18.8018 29.1835 18.7934 29.0344C18.7934 29.0316 18.7921 29.0274 18.7921 29.0246V29.0177C18.7865 28.902 18.7837 28.7864 18.7837 28.6707C18.7837 26.2557 20.0532 24.1389 21.9609 22.9503C21.9623 22.9489 21.9651 22.9489 21.9665 22.9475C22.0933 22.8666 22.2243 22.7914 22.3581 22.7203C22.3581 22.7203 22.3595 22.7203 22.3595 22.7189C23.3029 22.2173 24.3787 21.933 25.5214 21.933C29.2421 21.933 32.2591 24.9486 32.2591 28.6707Z"></path><path d="M25.5214 14.0692C29.2421 14.0692 32.2591 11.0522 32.2591 7.33146C32.2591 3.61074 29.2421 0.59375 25.5214 0.59375C22.0529 0.59375 19.1962 3.21637 18.8255 6.58592C18.8185 6.67092 18.8116 6.75454 18.8018 6.83815C18.7893 7.00119 18.7837 7.16563 18.7837 7.33146C18.7837 9.73669 20.0434 11.8465 21.94 13.038C22.0891 13.116 22.2355 13.201 22.3776 13.2916C22.3783 13.2923 22.379 13.2926 22.3797 13.293C22.3804 13.2933 22.3811 13.2937 22.3818 13.2944C23.3196 13.7891 24.3871 14.0692 25.5214 14.0692Z"></path><path d="M19.3645 12.4113C20.2926 12.4113 21.1694 12.638 21.94 13.038C20.0434 11.8465 18.7837 9.73669 18.7837 7.33146C18.7837 7.16563 18.7893 7.00119 18.8018 6.83815C18.4688 9.76455 16.1385 12.0866 13.2065 12.4044C13.8545 13.1193 14.3785 13.9484 14.745 14.857C15.7497 13.3798 17.4443 12.4113 19.3645 12.4113Z"></path><path d="M14.7312 21.1249V21.1236C14.1279 20.2331 13.7767 19.1587 13.7767 18.0007V17.9728C13.7767 15.3084 12.2285 13.0035 9.9835 11.911C9.98141 11.9103 9.97967 11.9096 9.97793 11.9089C9.97619 11.9082 9.97444 11.9075 9.97235 11.9068C9.96817 11.904 9.96538 11.9026 9.9612 11.9012C9.95981 11.9012 9.95981 11.8998 9.95981 11.8998C9.9417 11.8915 9.92394 11.8831 9.90618 11.8747C9.8884 11.8664 9.87063 11.858 9.85251 11.8497C9.82046 11.8343 9.78701 11.819 9.75357 11.8051L9.74521 11.8009C8.91745 11.4372 8.0019 11.2351 7.03898 11.2351C3.31826 11.2351 0.30127 14.2521 0.30127 17.9728C0.30127 21.6935 3.31826 24.7105 7.03898 24.7105C7.98797 24.7105 8.89098 24.514 9.71037 24.1601C9.71246 24.1594 9.7142 24.1583 9.71594 24.1573C9.71768 24.1562 9.71943 24.1552 9.72152 24.1545C9.8107 24.1169 9.8985 24.0765 9.9849 24.0333L9.98629 24.0319C10.7625 23.6919 11.6181 23.5037 12.5197 23.5037C12.7524 23.5037 12.9824 23.5163 13.2081 23.54C13.2082 23.5399 13.2081 23.54 13.2081 23.54C15.0168 23.7365 16.5971 24.695 17.6185 26.0885C17.9195 25.1688 18.3752 24.3201 18.9563 23.5732C17.1964 23.4464 15.6635 22.5058 14.7312 21.1249Z"></path><g clip-path="url(#clip0)"><path d="M106.391 18.0021C106.391 11.3724 101.039 6 94.4389 6H88.4585C81.8581 6 76.5061 11.3724 76.5061 18.0021V30.0042H81.2845V18.0021C81.2845 14.0268 84.4941 10.8008 88.4585 10.8008H94.4347C98.395 10.8008 101.609 14.0226 101.609 18.0021V30.0042H106.391V18.0021Z"></path><path d="M149.432 6H142.258C135.653 6 130.301 11.3724 130.301 18.0021C130.301 24.6319 135.653 30.0042 142.258 30.0042H149.432C156.036 30.0042 161.388 24.6319 161.388 18.0021C161.388 11.3724 156.032 6 149.432 6ZM149.432 25.1992H142.258C138.297 25.1992 135.084 21.9774 135.084 17.9979C135.084 14.0183 138.293 10.7966 142.258 10.7966H149.432C153.392 10.7966 156.606 14.0183 156.606 17.9979C156.606 21.9774 153.392 25.1992 149.432 25.1992Z"></path><path d="M74.1151 25.1992H58.5736C55.4526 25.1992 52.804 23.1924 51.8171 20.3983H74.1151V17.9979C74.1151 17.1808 74.1868 16.3807 74.3175 15.5975H51.8171C52.804 12.8033 55.4526 10.7966 58.5736 10.7966H76.0383C77.1475 8.87458 78.6911 7.22773 80.5299 6H58.5736C51.969 6 46.6169 11.3724 46.6169 18.0021C46.6169 24.6276 51.969 30 58.5736 30H74.1151V25.1992Z"></path><path d="M120.74 6H115.958H102.369C104.212 7.22773 105.751 8.87458 106.861 10.8008H115.958V30H120.74V10.8008H129.838C130.947 8.87458 132.486 7.22773 134.329 6H120.74Z"></path><path d="M182.906 15.6017H169.756C168.436 15.6017 167.365 14.5264 167.365 13.2013C167.365 11.8762 168.436 10.8008 169.756 10.8008H188.882V6H169.756C165.796 6 162.582 9.22173 162.582 13.2013C162.582 17.1808 165.791 20.4025 169.756 20.4025H182.906C184.226 20.4025 185.297 21.4779 185.297 22.803C185.297 24.1281 184.226 25.2034 182.906 25.2034H161.852C160.743 27.1297 159.199 28.7765 157.361 30.0042H182.906C186.866 30.0042 190.08 26.7825 190.08 22.803C190.08 18.8234 186.866 15.6017 182.906 15.6017Z"></path></g><defs><clipPath id="clip0"><rect width="190" height="24" fill="white" transform="translate(0 6)"></rect></clipPath></defs></svg>
|
||||
<div>
|
||||
Entos Envision
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<script>
|
||||
AlphaOrbitalsExample.init('app')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
222
src/examples/alpha-orbitals/index.ts
Normal file
222
src/examples/alpha-orbitals/index.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { debounceTime, skip } from 'rxjs/operators';
|
||||
import { AlphaOrbital, Basis } from '../../extensions/alpha-orbitals/data-model';
|
||||
import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/spherical-functions';
|
||||
import { BasisAndOrbitals, CreateOrbitalDensityVolume, CreateOrbitalRepresentation3D, CreateOrbitalVolume, StaticBasisAndOrbitals } from '../../extensions/alpha-orbitals/transforms';
|
||||
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { createPluginAsync } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { StateObjectSelector, StateTransformer } from '../../mol-state';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { ParamDefinition } from '../../mol-util/param-definition';
|
||||
import { mountControls } from './controls';
|
||||
import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
|
||||
import './index.html';
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
|
||||
interface DemoInput {
|
||||
moleculeSdf: string,
|
||||
basis: Basis,
|
||||
order: SphericalBasisOrder,
|
||||
orbitals: AlphaOrbital[]
|
||||
}
|
||||
|
||||
interface Params {
|
||||
show: { name: 'orbital', params: { index: number } } | { name: 'density', params: {} },
|
||||
isoValue: number,
|
||||
gpuSurface: boolean
|
||||
}
|
||||
|
||||
type Selectors = {
|
||||
type: 'orbital',
|
||||
volume: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalVolume>,
|
||||
positive: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
|
||||
negative: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
|
||||
} | {
|
||||
type: 'density',
|
||||
volume: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalDensityVolume>,
|
||||
positive: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
|
||||
}
|
||||
|
||||
export class AlphaOrbitalsExample {
|
||||
plugin: PluginUIContext;
|
||||
|
||||
async init(target: string | HTMLElement) {
|
||||
const defaultSpec = DefaultPluginUISpec();
|
||||
this.plugin = await createPluginAsync(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...defaultSpec,
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: false,
|
||||
showControls: false
|
||||
},
|
||||
},
|
||||
components: {
|
||||
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' },
|
||||
},
|
||||
canvas3d: {
|
||||
camera: {
|
||||
helper: { axes: { name: 'off', params: { } } }
|
||||
}
|
||||
},
|
||||
config: [
|
||||
[PluginConfig.Viewport.ShowExpand, false],
|
||||
[PluginConfig.Viewport.ShowControls, false],
|
||||
[PluginConfig.Viewport.ShowSelectionMode, false],
|
||||
[PluginConfig.Viewport.ShowAnimation, false],
|
||||
]
|
||||
});
|
||||
|
||||
this.plugin.managers.interactivity.setProps({ granularity: 'element' });
|
||||
|
||||
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
|
||||
PluginCommands.Toast.Show(this.plugin, {
|
||||
title: 'Error',
|
||||
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.load({
|
||||
moleculeSdf: DemoMoleculeSDF,
|
||||
...DemoOrbitals
|
||||
});
|
||||
|
||||
mountControls(this, document.getElementById('controls')!);
|
||||
}
|
||||
|
||||
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);
|
||||
readonly state = new BehaviorSubject<Params>({ show: { name: 'orbital', params: { index: 32 } }, isoValue: 1, gpuSurface: false });
|
||||
|
||||
private selectors?: Selectors = void 0;
|
||||
private basis?: StateObjectSelector<BasisAndOrbitals> = void 0;
|
||||
|
||||
private currentParams: Params = { ...this.state.value };
|
||||
|
||||
private clearVolume() {
|
||||
if (!this.selectors) return;
|
||||
const v = this.selectors.volume;
|
||||
this.selectors = void 0;
|
||||
return this.plugin.build().delete(v).commit();
|
||||
}
|
||||
|
||||
private async syncVolume() {
|
||||
if (!this.basis?.isOk) return;
|
||||
|
||||
const state = this.state.value;
|
||||
|
||||
if (state.show.name !== this.selectors?.type) {
|
||||
await this.clearVolume();
|
||||
}
|
||||
|
||||
const update = this.plugin.build();
|
||||
if (state.show.name === 'orbital') {
|
||||
if (!this.selectors) {
|
||||
const volume = update
|
||||
.to(this.basis)
|
||||
.apply(CreateOrbitalVolume, { index: state.show.params.index });
|
||||
|
||||
const positive = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('positive', ColorNames.blue)).selector;
|
||||
const negative = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('negative', ColorNames.red)).selector;
|
||||
|
||||
this.selectors = { type: 'orbital', volume: volume.selector, positive, negative };
|
||||
} else {
|
||||
const index = state.show.params.index;
|
||||
update.to(this.selectors.volume).update(CreateOrbitalVolume, () => ({ index }));
|
||||
}
|
||||
} else {
|
||||
if (!this.selectors) {
|
||||
const volume = update
|
||||
.to(this.basis)
|
||||
.apply(CreateOrbitalDensityVolume);
|
||||
const positive = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('positive', ColorNames.blue)).selector;
|
||||
this.selectors = { type: 'density', volume: volume.selector, positive };
|
||||
}
|
||||
}
|
||||
|
||||
await update.commit();
|
||||
|
||||
if (this.currentParams.gpuSurface !== this.state.value.gpuSurface) {
|
||||
await this.setIsovalue();
|
||||
}
|
||||
|
||||
this.currentParams = this.state.value;
|
||||
}
|
||||
|
||||
private setIsovalue() {
|
||||
if (!this.selectors) return;
|
||||
|
||||
this.currentParams = this.state.value;
|
||||
const update = this.plugin.build();
|
||||
update.to(this.selectors.positive).update(this.volumeParams('positive', ColorNames.blue));
|
||||
if (this.selectors?.type === 'orbital') {
|
||||
update.to(this.selectors.negative).update(this.volumeParams('negative', ColorNames.red));
|
||||
}
|
||||
return update.commit();
|
||||
}
|
||||
|
||||
private volumeParams(kind: 'positive' | 'negative', color: Color): StateTransformer.Params<typeof CreateOrbitalRepresentation3D> {
|
||||
return {
|
||||
alpha: 0.85,
|
||||
color,
|
||||
directVolume: this.state.value.gpuSurface,
|
||||
kind,
|
||||
relativeIsovalue: this.state.value.isoValue,
|
||||
pickable: false,
|
||||
xrayShaded: true,
|
||||
tryUseGpu: false
|
||||
};
|
||||
}
|
||||
|
||||
async load(input: DemoInput) {
|
||||
await this.plugin.clear();
|
||||
|
||||
const data = await this.plugin.builders.data.rawData({ data: input.moleculeSdf }, { state: { isGhost: true } });
|
||||
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, 'mol');
|
||||
const model = await this.plugin.builders.structure.createModel(trajectory);
|
||||
const structure = await this.plugin.builders.structure.createStructure(model);
|
||||
|
||||
const all = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'all');
|
||||
if (all) await this.plugin.builders.structure.representation.addRepresentation(all, { type: 'ball-and-stick', color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } });
|
||||
|
||||
|
||||
this.basis = await this.plugin.build().toRoot()
|
||||
.apply(StaticBasisAndOrbitals, { basis: input.basis, order: input.order, orbitals: input.orbitals })
|
||||
.commit();
|
||||
|
||||
await this.syncVolume();
|
||||
|
||||
this.params.next({
|
||||
show: ParamDefinition.MappedStatic('orbital', {
|
||||
'orbital': ParamDefinition.Group({
|
||||
index: ParamDefinition.Numeric(32, { min: 0, max: input.orbitals.length - 1 }, { immediateUpdate: true, isEssential: true }),
|
||||
}),
|
||||
'density': ParamDefinition.EmptyGroup()
|
||||
}, { cycle: true }),
|
||||
isoValue: ParamDefinition.Numeric(this.currentParams.isoValue, { min: 0.5, max: 3, step: 0.1 }, { immediateUpdate: true, isEssential: false }),
|
||||
gpuSurface: ParamDefinition.Boolean(this.currentParams.gpuSurface, { isHidden: true })
|
||||
});
|
||||
|
||||
this.state.pipe(skip(1), debounceTime(1000 / 24)).subscribe(async params => {
|
||||
if (params.show.name !== this.currentParams.show.name
|
||||
|| (params.show.name === 'orbital' && this.currentParams.show.name === 'orbital' && params.show.params.index !== this.currentParams.show.params.index)) {
|
||||
this.syncVolume();
|
||||
} else if (params.isoValue !== this.currentParams.isoValue || params.gpuSurface !== this.currentParams.gpuSurface) {
|
||||
this.setIsovalue();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { CustomElementProperty } from '../../mol-model-props/common/custom-element-property';
|
||||
@@ -9,22 +10,21 @@ import { Model, ElementIndex } from '../../mol-model/structure';
|
||||
import { Color } from '../../mol-util/color';
|
||||
|
||||
export const StripedResidues = CustomElementProperty.create<number>({
|
||||
isStatic: true,
|
||||
label: 'Residue Stripes',
|
||||
name: 'basic-wrapper-residue-striping',
|
||||
display: 'Residue Stripes',
|
||||
getData(model: Model) {
|
||||
const map = new Map<ElementIndex, number>();
|
||||
const residueIndex = model.atomicHierarchy.residueAtomSegments.index;
|
||||
for (let i = 0, _i = model.atomicHierarchy.atoms._rowCount; i < _i; i++) {
|
||||
map.set(i as ElementIndex, residueIndex[i] % 2);
|
||||
}
|
||||
return map;
|
||||
return { value: map };
|
||||
},
|
||||
coloring: {
|
||||
getColor(e) { return e === 0 ? Color(0xff0000) : Color(0x0000ff) },
|
||||
getColor(e) { return e === 0 ? Color(0xff0000) : Color(0x0000ff); },
|
||||
defaultColor: Color(0x777777)
|
||||
},
|
||||
format(e) {
|
||||
return e === 0 ? 'Odd stripe' : 'Even stripe'
|
||||
getLabel(e) {
|
||||
return e === 0 ? 'Odd stripe' : 'Even stripe';
|
||||
}
|
||||
})
|
||||
});
|
||||
15
src/examples/basic-wrapper/controls.tsx
Normal file
15
src/examples/basic-wrapper/controls.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { PluginUIComponent } from '../../mol-plugin-ui/base';
|
||||
|
||||
export class CustomToastMessage extends PluginUIComponent {
|
||||
render() {
|
||||
return <>
|
||||
Custom <i>Toast</i> content. No timeout.
|
||||
</>;
|
||||
}
|
||||
}
|
||||
51
src/examples/basic-wrapper/custom-theme.ts
Normal file
51
src/examples/basic-wrapper/custom-theme.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { isPositionLocation } from '../../mol-geo/util/location-iterator';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { ColorTheme } from '../../mol-theme/color';
|
||||
import { ThemeDataContext } from '../../mol-theme/theme';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
|
||||
export function CustomColorTheme(
|
||||
ctx: ThemeDataContext,
|
||||
props: PD.Values<{}>
|
||||
): ColorTheme<{}> {
|
||||
const { radius, center } = ctx.structure?.boundary.sphere!;
|
||||
const radiusSq = Math.max(radius * radius, 0.001);
|
||||
const scale = ColorTheme.PaletteScale;
|
||||
|
||||
return {
|
||||
factory: CustomColorTheme,
|
||||
granularity: 'vertex',
|
||||
color: location => {
|
||||
if (!isPositionLocation(location)) return ColorNames.black;
|
||||
const dist = Vec3.squaredDistance(location.position, center);
|
||||
const t = Math.min(dist / radiusSq, 1);
|
||||
return ((t * scale) | 0) as Color;
|
||||
},
|
||||
palette: {
|
||||
filter: 'nearest',
|
||||
colors: [
|
||||
ColorNames.red,
|
||||
ColorNames.pink,
|
||||
ColorNames.violet,
|
||||
ColorNames.orange,
|
||||
ColorNames.yellow,
|
||||
ColorNames.green,
|
||||
ColorNames.blue
|
||||
]
|
||||
},
|
||||
props: props,
|
||||
description: '',
|
||||
};
|
||||
}
|
||||
|
||||
export const CustomColorThemeProvider: ColorTheme.Provider<{}, 'basic-wrapper-custom-color-theme'> = {
|
||||
name: 'basic-wrapper-custom-color-theme',
|
||||
label: 'Custom Color Theme',
|
||||
category: ColorTheme.Category.Misc,
|
||||
factory: CustomColorTheme,
|
||||
getParams: () => ({}),
|
||||
defaultValues: { },
|
||||
isApplicable: (ctx: ThemeDataContext) => true,
|
||||
};
|
||||
@@ -41,7 +41,7 @@
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="app.css" />
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
<script type="text/javascript" src="./index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -50,18 +50,18 @@
|
||||
<input type='text' id='url' placeholder='url' />
|
||||
<input type='text' id='assemblyId' placeholder='assembly id' />
|
||||
<select id='format'>
|
||||
<option value='cif' selected>CIF</option>
|
||||
<option value='mmcif' selected>mmCIF</option>
|
||||
<option value='pdb'>PDB</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
<script>
|
||||
function $(id) { return document.getElementById(id); }
|
||||
|
||||
|
||||
var pdbId = '1grm', assemblyId= '1';
|
||||
var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
|
||||
var format = 'cif';
|
||||
|
||||
var format = 'mmcif';
|
||||
|
||||
$('url').value = url;
|
||||
$('url').onchange = function (e) { url = e.target.value; }
|
||||
$('assemblyId').value = assemblyId;
|
||||
@@ -69,15 +69,8 @@
|
||||
$('format').value = format;
|
||||
$('format').onchange = function (e) { format = e.target.value; }
|
||||
|
||||
// var url = 'https://www.ebi.ac.uk/pdbe/entry-files/pdb' + pdbId + '.ent';
|
||||
// var format = 'pdb';
|
||||
// var assemblyId = 'deposited';
|
||||
|
||||
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
|
||||
BasicMolStarWrapper.setBackground(0xffffff);
|
||||
// BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId });
|
||||
// BasicMolStarWrapper.toggleSpin();
|
||||
|
||||
|
||||
addControl('Load Asym Unit', () => BasicMolStarWrapper.load({ url: url, format: format }));
|
||||
addControl('Load Assembly', () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId }));
|
||||
@@ -86,14 +79,14 @@
|
||||
|
||||
addHeader('Camera');
|
||||
addControl('Toggle Spin', () => BasicMolStarWrapper.toggleSpin());
|
||||
|
||||
|
||||
addSeparator();
|
||||
|
||||
addHeader('Animation');
|
||||
|
||||
// adjust this number to make the animation faster or slower
|
||||
// requires to "restart" the animation if changed
|
||||
BasicMolStarWrapper.animate.modelIndex.maxFPS = 30;
|
||||
BasicMolStarWrapper.animate.modelIndex.targetFps = 30;
|
||||
|
||||
addControl('Play To End', () => BasicMolStarWrapper.animate.modelIndex.onceForward());
|
||||
addControl('Play To Start', () => BasicMolStarWrapper.animate.modelIndex.onceBackward());
|
||||
@@ -104,11 +97,21 @@
|
||||
addHeader('Misc');
|
||||
|
||||
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
|
||||
addControl('Apply Custom Theme', () => BasicMolStarWrapper.coloring.applyCustomTheme());
|
||||
addControl('Default Coloring', () => BasicMolStarWrapper.coloring.applyDefault());
|
||||
|
||||
addHeader('Interactivity');
|
||||
addControl('Highlight seq_id=7', () => BasicMolStarWrapper.interactivity.highlightOn());
|
||||
addControl('Clear Highlight', () => BasicMolStarWrapper.interactivity.clearHighlight());
|
||||
|
||||
addHeader('Tests');
|
||||
|
||||
addControl('Static Superposition', () => BasicMolStarWrapper.tests.staticSuperposition());
|
||||
addControl('Dynamic Superposition', () => BasicMolStarWrapper.tests.dynamicSuperposition());
|
||||
addControl('Validation Tooltip', () => BasicMolStarWrapper.tests.toggleValidationTooltip());
|
||||
|
||||
addControl('Show Toasts', () => BasicMolStarWrapper.tests.showToasts());
|
||||
addControl('Hide Toasts', () => BasicMolStarWrapper.tests.hideToasts());
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
174
src/examples/basic-wrapper/index.ts
Normal file
174
src/examples/basic-wrapper/index.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
|
||||
import { EmptyLoci } from '../../mol-model/loci';
|
||||
import { StructureSelection } from '../../mol-model/structure';
|
||||
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { Script } from '../../mol-script/script';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { StripedResidues } from './coloring';
|
||||
import { CustomToastMessage } from './controls';
|
||||
import { CustomColorThemeProvider } from './custom-theme';
|
||||
import './index.html';
|
||||
import { buildStaticSuperposition, dynamicSuperpositionTest, StaticSuperpositionTestData } from './superposition';
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
|
||||
type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: boolean, assemblyId?: string }
|
||||
|
||||
class BasicWrapper {
|
||||
plugin: PluginUIContext;
|
||||
|
||||
init(target: string | HTMLElement) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginUISpec(),
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: false,
|
||||
showControls: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
remoteState: 'none'
|
||||
}
|
||||
});
|
||||
|
||||
this.plugin.representation.structure.themes.colorThemeRegistry.add(StripedResidues.colorThemeProvider!);
|
||||
this.plugin.representation.structure.themes.colorThemeRegistry.add(CustomColorThemeProvider);
|
||||
this.plugin.managers.lociLabels.addProvider(StripedResidues.labelProvider!);
|
||||
this.plugin.customModelProperties.register(StripedResidues.propertyProvider, true);
|
||||
}
|
||||
|
||||
async load({ url, format = 'mmcif', isBinary = false, assemblyId = '' }: LoadParams) {
|
||||
await this.plugin.clear();
|
||||
|
||||
const data = await this.plugin.builders.data.download({ url: Asset.Url(url), isBinary }, { state: { isGhost: true } });
|
||||
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
|
||||
|
||||
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default', {
|
||||
structure: assemblyId ? {
|
||||
name: 'assembly',
|
||||
params: { id: assemblyId }
|
||||
} : {
|
||||
name: 'model',
|
||||
params: { }
|
||||
},
|
||||
showUnitcell: false,
|
||||
representationPreset: 'auto'
|
||||
});
|
||||
}
|
||||
|
||||
setBackground(color: number) {
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: props => { props.renderer.backgroundColor = Color(color); } });
|
||||
}
|
||||
|
||||
toggleSpin() {
|
||||
if (!this.plugin.canvas3d) return;
|
||||
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, {
|
||||
settings: props => {
|
||||
props.trackball.spin = !props.trackball.spin;
|
||||
}
|
||||
});
|
||||
if (!this.plugin.canvas3d.props.trackball.spin) PluginCommands.Camera.Reset(this.plugin, {});
|
||||
}
|
||||
|
||||
private animateModelIndexTargetFps() {
|
||||
return Math.max(1, this.animate.modelIndex.targetFps | 0);
|
||||
}
|
||||
|
||||
animate = {
|
||||
modelIndex: {
|
||||
targetFps: 8,
|
||||
onceForward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'forward' } } }); },
|
||||
onceBackward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'backward' } } }); },
|
||||
palindrome: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'palindrome', params: {} } }); },
|
||||
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: { direction: 'forward' } } }); },
|
||||
stop: () => this.plugin.managers.animation.stop()
|
||||
}
|
||||
}
|
||||
|
||||
coloring = {
|
||||
applyStripes: async () => {
|
||||
this.plugin.dataTransaction(async () => {
|
||||
for (const s of this.plugin.managers.structure.hierarchy.current.structures) {
|
||||
await this.plugin.managers.structure.component.updateRepresentationsTheme(s.components, { color: StripedResidues.propertyProvider.descriptor.name as any });
|
||||
}
|
||||
});
|
||||
},
|
||||
applyCustomTheme: async () => {
|
||||
this.plugin.dataTransaction(async () => {
|
||||
for (const s of this.plugin.managers.structure.hierarchy.current.structures) {
|
||||
await this.plugin.managers.structure.component.updateRepresentationsTheme(s.components, { color: CustomColorThemeProvider.name as any });
|
||||
}
|
||||
});
|
||||
},
|
||||
applyDefault: async () => {
|
||||
this.plugin.dataTransaction(async () => {
|
||||
for (const s of this.plugin.managers.structure.hierarchy.current.structures) {
|
||||
await this.plugin.managers.structure.component.updateRepresentationsTheme(s.components, { color: 'default' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interactivity = {
|
||||
highlightOn: () => {
|
||||
const data = this.plugin.managers.structure.hierarchy.current.structures[0]?.cell.obj?.data;
|
||||
if (!data) return;
|
||||
|
||||
const seq_id = 7;
|
||||
const sel = Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
|
||||
'residue-test': Q.core.rel.eq([Q.struct.atomProperty.macromolecular.label_seq_id(), seq_id]),
|
||||
'group-by': Q.struct.atomProperty.macromolecular.residueKey()
|
||||
}), data);
|
||||
const loci = StructureSelection.toLociWithSourceUnits(sel);
|
||||
this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci });
|
||||
},
|
||||
clearHighlight: () => {
|
||||
this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
|
||||
}
|
||||
}
|
||||
|
||||
tests = {
|
||||
staticSuperposition: async () => {
|
||||
await this.plugin.clear();
|
||||
return buildStaticSuperposition(this.plugin, StaticSuperpositionTestData);
|
||||
},
|
||||
dynamicSuperposition: async () => {
|
||||
await this.plugin.clear();
|
||||
return dynamicSuperpositionTest(this.plugin, ['1tqn', '2hhb', '4hhb'], 'HEM');
|
||||
},
|
||||
toggleValidationTooltip: () => {
|
||||
return this.plugin.state.updateBehavior(PDBeStructureQualityReport, params => { params.showTooltip = !params.showTooltip; });
|
||||
},
|
||||
showToasts: () => {
|
||||
PluginCommands.Toast.Show(this.plugin, {
|
||||
title: 'Toast 1',
|
||||
message: 'This is an example text, timeout 3s',
|
||||
key: 'toast-1',
|
||||
timeoutMs: 3000
|
||||
});
|
||||
PluginCommands.Toast.Show(this.plugin, {
|
||||
title: 'Toast 2',
|
||||
message: CustomToastMessage,
|
||||
key: 'toast-2'
|
||||
});
|
||||
},
|
||||
hideToasts: () => {
|
||||
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-1' });
|
||||
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-2' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(window as any).BasicMolStarWrapper = new BasicWrapper();
|
||||
119
src/examples/basic-wrapper/superposition.ts
Normal file
119
src/examples/basic-wrapper/superposition.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Mat4 } from '../../mol-math/linear-algebra';
|
||||
import { QueryContext, StructureSelection } from '../../mol-model/structure';
|
||||
import { superpose } from '../../mol-model/structure/structure/util/superposition';
|
||||
import { PluginStateObject as PSO } from '../../mol-plugin-state/objects';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { Expression } from '../../mol-script/language/expression';
|
||||
import { compile } from '../../mol-script/runtime/query/compiler';
|
||||
import { StateObjectRef } from '../../mol-state';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
|
||||
export type SuperpositionTestInput = {
|
||||
pdbId: string,
|
||||
auth_asym_id: string,
|
||||
matrix: Mat4
|
||||
}[];
|
||||
|
||||
export function buildStaticSuperposition(plugin: PluginContext, src: SuperpositionTestInput) {
|
||||
return plugin.dataTransaction(async () => {
|
||||
for (const s of src) {
|
||||
const { structure } = await loadStructure(plugin, `https://www.ebi.ac.uk/pdbe/static/entry/${s.pdbId}_updated.cif`, 'mmcif');
|
||||
await transform(plugin, structure, s.matrix);
|
||||
const chain = await plugin.builders.structure.tryCreateComponentFromExpression(structure, chainSelection(s.auth_asym_id), `Chain ${s.auth_asym_id}`);
|
||||
if (chain) await plugin.builders.structure.representation.addRepresentation(chain, { type: 'cartoon' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const StaticSuperpositionTestData: SuperpositionTestInput = [
|
||||
{
|
||||
pdbId: '1aj5', auth_asym_id: 'A', matrix: Mat4.identity()
|
||||
},
|
||||
{
|
||||
pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows([
|
||||
[0.406, 0.879, 0.248, -200.633],
|
||||
[0.693, -0.473, 0.544, 73.403],
|
||||
[0.596, -0.049, -0.802, -14.209],
|
||||
[0, 0, 0, 1]])
|
||||
},
|
||||
{
|
||||
pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows([
|
||||
[-0.053, -0.077, 0.996, -45.633],
|
||||
[-0.312, 0.949, 0.057, -12.255],
|
||||
[-0.949, -0.307, -0.074, 53.562],
|
||||
[0, 0, 0, 1]])
|
||||
}
|
||||
];
|
||||
|
||||
export function dynamicSuperpositionTest(plugin: PluginContext, src: string[], comp_id: string) {
|
||||
return plugin.dataTransaction(async () => {
|
||||
for (const s of src) {
|
||||
await loadStructure(plugin, `https://www.ebi.ac.uk/pdbe/static/entry/${s}_updated.cif`, 'mmcif');
|
||||
}
|
||||
|
||||
const pivot = MS.struct.filter.first([
|
||||
MS.struct.generator.atomGroups({
|
||||
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
|
||||
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
|
||||
})
|
||||
]);
|
||||
|
||||
const rest = MS.struct.modifier.exceptBy({
|
||||
0: MS.struct.modifier.includeSurroundings({
|
||||
0: pivot,
|
||||
radius: 5
|
||||
}),
|
||||
by: pivot
|
||||
});
|
||||
|
||||
const query = compile<StructureSelection>(pivot);
|
||||
const xs = plugin.managers.structure.hierarchy.current.structures;
|
||||
const selections = xs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.cell.obj!.data))));
|
||||
|
||||
const transforms = superpose(selections);
|
||||
|
||||
await siteVisual(plugin, xs[0].cell, pivot, rest);
|
||||
for (let i = 1; i < selections.length; i++) {
|
||||
await transform(plugin, xs[i].cell, transforms[i - 1].bTransform);
|
||||
await siteVisual(plugin, xs[i].cell, pivot, rest);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function siteVisual(plugin: PluginContext, s: StateObjectRef<PSO.Molecule.Structure>, pivot: Expression, rest: Expression) {
|
||||
const center = await plugin.builders.structure.tryCreateComponentFromExpression(s, pivot, 'pivot');
|
||||
if (center) await plugin.builders.structure.representation.addRepresentation(center, { type: 'ball-and-stick', color: 'residue-name' });
|
||||
|
||||
const surr = await plugin.builders.structure.tryCreateComponentFromExpression(s, rest, 'rest');
|
||||
if (surr) await plugin.builders.structure.representation.addRepresentation(surr, { type: 'ball-and-stick', color: 'uniform', size: 'uniform', sizeParams: { value: 0.33 } });
|
||||
}
|
||||
|
||||
async function loadStructure(plugin: PluginContext, url: string, format: BuiltInTrajectoryFormat, assemblyId?: string) {
|
||||
const data = await plugin.builders.data.download({ url: Asset.Url(url) });
|
||||
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
|
||||
const model = await plugin.builders.structure.createModel(trajectory);
|
||||
const structure = await plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : void 0);
|
||||
|
||||
return { data, trajectory, model, structure };
|
||||
}
|
||||
|
||||
function chainSelection(auth_asym_id: string) {
|
||||
return MS.struct.generator.atomGroups({
|
||||
'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), auth_asym_id])
|
||||
});
|
||||
}
|
||||
|
||||
function transform(plugin: PluginContext, s: StateObjectRef<PSO.Molecule.Structure>, matrix: Mat4) {
|
||||
const b = plugin.state.data.build().to(s)
|
||||
.insert(StateTransforms.Model.TransformStructureConformation, { transform: { name: 'matrix', params: { data: matrix, transpose: false } } });
|
||||
return plugin.runTask(plugin.state.data.updateTree(b));
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Table } from '../../mol-data/db'
|
||||
import { CifWriter } from '../../mol-io/writer/cif'
|
||||
import * as S from './schemas'
|
||||
import { Table } from '../../mol-data/db';
|
||||
import { CifWriter } from '../../mol-io/writer/cif';
|
||||
import * as S from './schemas';
|
||||
// import { getCategoryInstanceProvider } from './utils'
|
||||
|
||||
export default function create(allData: any) {
|
||||
export function createMapping(allData: any) {
|
||||
const mols = Object.keys(allData);
|
||||
const enc = CifWriter.createEncoder();
|
||||
enc.startDataBlock(mols[0]);
|
||||
@@ -38,7 +38,7 @@ type MappingRow = Table.Row<S.mapping>;
|
||||
|
||||
function writeDomain(enc: CifWriter.Encoder, domain: DomainAnnotation | undefined) {
|
||||
if (!domain) return;
|
||||
enc.writeCategory({ name: `pdbx_${domain.name}_domain_annotation`, instance: () => CifWriter.Category.ofTable(domain.domains) });
|
||||
enc.writeCategory({ name: `pdbx_${domain.name}_domain_annotation`, instance: () => CifWriter.Category.ofTable(domain.domains) });
|
||||
enc.writeCategory({ name: `pdbx_${domain.name}_domain_mapping`, instance: () => CifWriter.Category.ofTable(domain.mappings) });
|
||||
}
|
||||
|
||||
@@ -4,21 +4,21 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Column } from '../../mol-data/db'
|
||||
import { Column } from '../../mol-data/db';
|
||||
|
||||
import Type = Column.Schema
|
||||
|
||||
export const Sources = {
|
||||
id: Type.str,
|
||||
count: Type.int
|
||||
}
|
||||
};
|
||||
export type Sources = typeof Sources
|
||||
|
||||
export const Base = {
|
||||
id: Type.str,
|
||||
identifier: Type.str,
|
||||
mapping_group_id: Type.int
|
||||
}
|
||||
};
|
||||
export type Base = typeof Base
|
||||
|
||||
export const mapping = {
|
||||
@@ -36,17 +36,17 @@ export const mapping = {
|
||||
end_label_seq_id: Type.int,
|
||||
end_auth_seq_id: Type.int,
|
||||
pdbx_end_PDB_ins_code: Type.str
|
||||
}
|
||||
};
|
||||
export type mapping = typeof mapping
|
||||
|
||||
export const Pfam = {
|
||||
description: Type.str
|
||||
}
|
||||
};
|
||||
export type Pfam = typeof Pfam
|
||||
|
||||
export const InterPro = {
|
||||
name: Type.str
|
||||
}
|
||||
};
|
||||
export type InterPro = typeof InterPro
|
||||
|
||||
export const CATH = {
|
||||
@@ -56,32 +56,32 @@ export const CATH = {
|
||||
identifier: Type.str,
|
||||
class: Type.str,
|
||||
topology: Type.str,
|
||||
}
|
||||
};
|
||||
export type CATH = typeof CATH
|
||||
|
||||
export const EC = {
|
||||
accepted_name: Type.str,
|
||||
reaction: Type.str,
|
||||
systematic_name: Type.str
|
||||
}
|
||||
};
|
||||
export type EC = typeof EC
|
||||
|
||||
export const UniProt = {
|
||||
name: Type.str
|
||||
}
|
||||
};
|
||||
export type UniProt = typeof UniProt
|
||||
|
||||
export const SCOP = {
|
||||
sccs: Type.str,
|
||||
description: Type.str
|
||||
}
|
||||
};
|
||||
export type SCOP = typeof SCOP
|
||||
|
||||
export const GO = {
|
||||
category: Type.str,
|
||||
definition: Type.str,
|
||||
name: Type.str
|
||||
}
|
||||
};
|
||||
export type GO = typeof GO
|
||||
|
||||
export const categories = {
|
||||
@@ -92,4 +92,4 @@ export const categories = {
|
||||
UniProt,
|
||||
SCOP,
|
||||
GO
|
||||
}
|
||||
};
|
||||
@@ -4,9 +4,9 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as express from 'express'
|
||||
import fetch from 'node-fetch'
|
||||
import createMapping from './mapping'
|
||||
import express from 'express';
|
||||
import fetch from 'node-fetch';
|
||||
import { createMapping } from './mapping';
|
||||
|
||||
async function getMappings(id: string) {
|
||||
const data = await fetch(`https://www.ebi.ac.uk/pdbe/api/mappings/${id}`);
|
||||
@@ -15,11 +15,11 @@ async function getMappings(id: string) {
|
||||
};
|
||||
|
||||
|
||||
let PORT = process.env.port || 1338;
|
||||
const PORT = process.env.port || 1338;
|
||||
|
||||
const app = express();
|
||||
|
||||
const PREFIX = '/'
|
||||
const PREFIX = '/';
|
||||
|
||||
app.get(`${PREFIX}/:id`, async (req, res) => {
|
||||
try {
|
||||
@@ -41,7 +41,7 @@ app.get(`${PREFIX}/:id`, async (req, res) => {
|
||||
app.get(`${PREFIX}`, (req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
|
||||
res.end('Usage: /pdb_id, e.g. /1tqn');
|
||||
})
|
||||
});
|
||||
|
||||
app.listen(PORT);
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import fetch from 'node-fetch'
|
||||
import createMapping from './mapping'
|
||||
import fetch from 'node-fetch';
|
||||
import { createMapping } from './mapping';
|
||||
|
||||
(async function () {
|
||||
const data = await fetch('https://www.ebi.ac.uk/pdbe/api/mappings/1tqn?pretty=true');
|
||||
87
src/examples/lighting/index.html
Normal file
87
src/examples/lighting/index.html
Normal file
@@ -0,0 +1,87 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<title>Mol* Lighting Demo</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#app {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
width: 150px;
|
||||
bottom: 100px;
|
||||
right: 50px;
|
||||
z-index: 10;
|
||||
font-family: sans-serif;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
#controls > button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
margin: 5px 0px;
|
||||
}
|
||||
|
||||
#controls > input, #controls > select {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
<script type="text/javascript" src="./index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id='controls'></div>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
LightingDemo.init('app')
|
||||
LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3)
|
||||
|
||||
addHeader('Example PDB IDs');
|
||||
addControl('4KTC', () => LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3));
|
||||
addControl('5FJ5', () => LightingDemo.load({ url: 'https://models.rcsb.org/5FJ5.bcif', assemblyId: '1' }, 8, 1.8));
|
||||
addControl('1UPN', () => LightingDemo.load({ url: 'https://models.rcsb.org/1UPN.bcif', assemblyId: '1' }, 7, 1.6));
|
||||
addControl('1RB8', () => LightingDemo.load({ url: 'https://models.rcsb.org/1RB8.bcif', assemblyId: '1' }, 6, 1.3));
|
||||
|
||||
addSeparator()
|
||||
|
||||
addHeader('Lighting Presets');
|
||||
addControl('Illustrative', () => LightingDemo.setPreset('illustrative'));
|
||||
addControl('Standard', () => LightingDemo.setPreset('standard'));
|
||||
addControl('Ambient Occlusion', () => LightingDemo.setPreset('occlusion'));
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
function $(id) { return document.getElementById(id); }
|
||||
|
||||
function addControl(label, action) {
|
||||
var btn = document.createElement('button');
|
||||
btn.onclick = action;
|
||||
btn.innerText = label;
|
||||
$('controls').appendChild(btn);
|
||||
}
|
||||
|
||||
function addSeparator() {
|
||||
var hr = document.createElement('br');
|
||||
$('controls').appendChild(hr);
|
||||
}
|
||||
|
||||
function addHeader(header) {
|
||||
var h = document.createElement('h3');
|
||||
h.innerText = header;
|
||||
$('controls').appendChild(h);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
131
src/examples/lighting/index.ts
Normal file
131
src/examples/lighting/index.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Canvas3DProps } from '../../mol-canvas3d/canvas3d';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import './index.html';
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
|
||||
type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: boolean, assemblyId?: string }
|
||||
|
||||
type _Preset = Pick<Canvas3DProps, 'multiSample' | 'postprocessing' | 'renderer'>
|
||||
type Preset = { [K in keyof _Preset]: Partial<_Preset[K]> }
|
||||
|
||||
const Canvas3DPresets = {
|
||||
illustrative: <Preset> {
|
||||
multiSample: {
|
||||
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.1 } }
|
||||
},
|
||||
renderer: {
|
||||
style: { name: 'flat', params: {} }
|
||||
}
|
||||
},
|
||||
occlusion: <Preset> {
|
||||
multiSample: {
|
||||
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'off', params: { } }
|
||||
},
|
||||
renderer: {
|
||||
style: { name: 'matte', params: {} }
|
||||
}
|
||||
},
|
||||
standard: <Preset> {
|
||||
multiSample: {
|
||||
mode: 'off' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'off', params: { } },
|
||||
outline: { name: 'off', params: { } }
|
||||
},
|
||||
renderer: {
|
||||
style: { name: 'matte', params: {} }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
type Canvas3DPreset = keyof typeof Canvas3DPresets
|
||||
|
||||
class LightingDemo {
|
||||
plugin: PluginUIContext;
|
||||
|
||||
private radius = 5;
|
||||
private bias = 1.1;
|
||||
private preset: Canvas3DPreset = 'illustrative';
|
||||
|
||||
init(target: string | HTMLElement) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginUISpec(),
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: false,
|
||||
showControls: false
|
||||
},
|
||||
},
|
||||
components: {
|
||||
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' }
|
||||
}
|
||||
});
|
||||
|
||||
this.setPreset('illustrative');
|
||||
}
|
||||
|
||||
setPreset(preset: Canvas3DPreset) {
|
||||
const props = Canvas3DPresets[preset];
|
||||
if (props.postprocessing.occlusion?.name === 'on') {
|
||||
props.postprocessing.occlusion.params.radius = this.radius;
|
||||
props.postprocessing.occlusion.params.bias = this.bias;
|
||||
}
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
|
||||
...props,
|
||||
multiSample: {
|
||||
...this.plugin.canvas3d!.props.multiSample,
|
||||
...props.multiSample
|
||||
},
|
||||
renderer: {
|
||||
...this.plugin.canvas3d!.props.renderer,
|
||||
...props.renderer
|
||||
},
|
||||
postprocessing: {
|
||||
...this.plugin.canvas3d!.props.postprocessing,
|
||||
...props.postprocessing
|
||||
},
|
||||
} });
|
||||
}
|
||||
|
||||
async load({ url, format = 'mmcif', isBinary = true, assemblyId = '' }: LoadParams, radius: number, bias: number) {
|
||||
await this.plugin.clear();
|
||||
|
||||
const data = await this.plugin.builders.data.download({ url: Asset.Url(url), isBinary }, { state: { isGhost: true } });
|
||||
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
|
||||
const model = await this.plugin.builders.structure.createModel(trajectory);
|
||||
const structure = await this.plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : { name: 'model', params: { } });
|
||||
|
||||
const polymer = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'polymer');
|
||||
if (polymer) await this.plugin.builders.structure.representation.addRepresentation(polymer, { type: 'spacefill', color: 'illustrative' });
|
||||
|
||||
const ligand = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'ligand');
|
||||
if (ligand) await this.plugin.builders.structure.representation.addRepresentation(ligand, { type: 'ball-and-stick', color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } });
|
||||
|
||||
this.radius = radius;
|
||||
this.bias = bias;
|
||||
this.setPreset(this.preset);
|
||||
}
|
||||
}
|
||||
|
||||
(window as any).LightingDemo = new LightingDemo();
|
||||
@@ -1,12 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { CustomElementProperty } from '../../mol-model-props/common/custom-element-property';
|
||||
import { Model, ElementIndex, ResidueIndex } from '../../mol-model/structure';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { CustomProperty } from '../../mol-model-props/common/custom-property';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
|
||||
const EvolutionaryConservationPalette: Color[] = [
|
||||
[255, 255, 129], // insufficient
|
||||
@@ -23,14 +26,14 @@ const EvolutionaryConservationPalette: Color[] = [
|
||||
const EvolutionaryConservationDefaultColor = Color(0x999999);
|
||||
|
||||
export const EvolutionaryConservation = CustomElementProperty.create<number>({
|
||||
isStatic: true,
|
||||
name: 'proteopedia-wrapper-evolutionary-conservation',
|
||||
display: 'Evolutionary Conservation',
|
||||
async getData(model: Model) {
|
||||
const id = model.label.toLowerCase();
|
||||
const req = await fetch(`https://proteopedia.org/cgi-bin/cnsrf?${id}`);
|
||||
const json = await req.json();
|
||||
const annotations = (json && json.residueAnnotations) || [];
|
||||
label: 'Evolutionary Conservation',
|
||||
type: 'static',
|
||||
async getData(model: Model, ctx: CustomProperty.Context) {
|
||||
const id = model.entryId.toLowerCase();
|
||||
const url = Asset.getUrlAsset(ctx.assetManager, `https://proteopedia.org/cgi-bin/cnsrf?${id}`);
|
||||
const json = await ctx.assetManager.resolve(url, 'json').runInContext(ctx.runtime);
|
||||
const annotations = json.data?.residueAnnotations || [];
|
||||
|
||||
const conservationMap = new Map<string, number>();
|
||||
|
||||
@@ -56,7 +59,7 @@ export const EvolutionaryConservation = CustomElementProperty.create<number>({
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
return { value: map, assets: [json] };
|
||||
},
|
||||
coloring: {
|
||||
getColor(e: number) {
|
||||
@@ -65,8 +68,8 @@ export const EvolutionaryConservation = CustomElementProperty.create<number>({
|
||||
},
|
||||
defaultColor: EvolutionaryConservationDefaultColor
|
||||
},
|
||||
format(e) {
|
||||
if (e === 10) return `Evolutionary Conservation: InsufficientData`;
|
||||
getLabel(e) {
|
||||
if (e === 10) return `Evolutionary Conservation: Insufficient Data`;
|
||||
return e ? `Evolutionary Conservation: ${e}` : void 0;
|
||||
}
|
||||
});
|
||||
@@ -1,3 +1,18 @@
|
||||
== v3.4 ==
|
||||
|
||||
* Fixed HET group reset.
|
||||
* Updated core.
|
||||
* Removed Camera Cliping.
|
||||
|
||||
== v3.3 ==
|
||||
|
||||
* Camera Clipping.
|
||||
|
||||
== v3.2 ==
|
||||
|
||||
* Fixed assembly loading.
|
||||
* Better HET group focus.
|
||||
|
||||
== v3.0 ==
|
||||
|
||||
* Fixed initial camera zoom.
|
||||
|
||||
@@ -6,82 +6,82 @@
|
||||
*/
|
||||
|
||||
|
||||
import { Unit, StructureProperties, StructureElement, Link } from '../../mol-model/structure';
|
||||
import { Unit, StructureProperties, StructureElement, Bond } from '../../mol-model/structure';
|
||||
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { Location } from '../../mol-model/location';
|
||||
import { ColorTheme, LocationColor } from '../../mol-theme/color';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition'
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { ThemeDataContext } from '../../mol-theme/theme';
|
||||
import { Column } from '../../mol-data/db';
|
||||
|
||||
const Description = 'Gives every chain a color from a list based on its `asym_id` value.'
|
||||
const Description = 'Gives every chain a color from a list based on its `asym_id` value.';
|
||||
|
||||
export function createProteopediaCustomTheme(colors: number[]) {
|
||||
const ProteopediaCustomColorThemeParams = {
|
||||
colors: PD.ObjectList({ color: PD.Color(Color(0xffffff)) }, ({ color }) => Color.toHexString(color),
|
||||
{ defaultValue: colors.map(c => ({ color: Color(c) })) })
|
||||
}
|
||||
};
|
||||
type ProteopediaCustomColorThemeParams = typeof ProteopediaCustomColorThemeParams
|
||||
function getChainIdColorThemeParams(ctx: ThemeDataContext) {
|
||||
return ProteopediaCustomColorThemeParams // TODO return copy
|
||||
return ProteopediaCustomColorThemeParams; // TODO return copy
|
||||
}
|
||||
|
||||
function getAsymId(unit: Unit): StructureElement.Property<string> {
|
||||
switch (unit.kind) {
|
||||
case Unit.Kind.Atomic:
|
||||
return StructureProperties.chain.label_asym_id
|
||||
return StructureProperties.chain.label_asym_id;
|
||||
case Unit.Kind.Spheres:
|
||||
case Unit.Kind.Gaussians:
|
||||
return StructureProperties.coarse.asym_id
|
||||
return StructureProperties.coarse.asym_id;
|
||||
}
|
||||
}
|
||||
|
||||
function addAsymIds(map: Map<string, number>, data: Column<string>) {
|
||||
let j = map.size
|
||||
let j = map.size;
|
||||
for (let o = 0, ol = data.rowCount; o < ol; ++o) {
|
||||
const k = data.value(o)
|
||||
const k = data.value(o);
|
||||
if (!map.has(k)) {
|
||||
map.set(k, j)
|
||||
j += 1
|
||||
map.set(k, j);
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ProteopediaCustomColorTheme(ctx: ThemeDataContext, props: PD.Values<ProteopediaCustomColorThemeParams>): ColorTheme<ProteopediaCustomColorThemeParams> {
|
||||
let color: LocationColor
|
||||
let color: LocationColor;
|
||||
|
||||
const colors = props.colors, colorCount = colors.length, defaultColor = colors[0].color;
|
||||
|
||||
if (ctx.structure) {
|
||||
const l = StructureElement.create()
|
||||
const { models } = ctx.structure
|
||||
const asymIdSerialMap = new Map<string, number>()
|
||||
const l = StructureElement.Location.create(ctx.structure);
|
||||
const { models } = ctx.structure;
|
||||
const asymIdSerialMap = new Map<string, number>();
|
||||
for (let i = 0, il = models.length; i < il; ++i) {
|
||||
const m = models[i]
|
||||
addAsymIds(asymIdSerialMap, m.atomicHierarchy.chains.label_asym_id)
|
||||
const m = models[i];
|
||||
addAsymIds(asymIdSerialMap, m.atomicHierarchy.chains.label_asym_id);
|
||||
if (m.coarseHierarchy.isDefined) {
|
||||
addAsymIds(asymIdSerialMap, m.coarseHierarchy.spheres.asym_id)
|
||||
addAsymIds(asymIdSerialMap, m.coarseHierarchy.gaussians.asym_id)
|
||||
addAsymIds(asymIdSerialMap, m.coarseHierarchy.spheres.asym_id);
|
||||
addAsymIds(asymIdSerialMap, m.coarseHierarchy.gaussians.asym_id);
|
||||
}
|
||||
}
|
||||
|
||||
color = (location: Location): Color => {
|
||||
if (StructureElement.isLocation(location)) {
|
||||
if (StructureElement.Location.is(location)) {
|
||||
const asym_id = getAsymId(location.unit);
|
||||
const o = asymIdSerialMap.get(asym_id(location)) || 0;
|
||||
return colors[o % colorCount].color;
|
||||
} else if (Link.isLocation(location)) {
|
||||
const asym_id = getAsymId(location.aUnit)
|
||||
l.unit = location.aUnit
|
||||
l.element = location.aUnit.elements[location.aIndex]
|
||||
} else if (Bond.isLocation(location)) {
|
||||
const asym_id = getAsymId(location.aUnit);
|
||||
l.unit = location.aUnit;
|
||||
l.element = location.aUnit.elements[location.aIndex];
|
||||
const o = asymIdSerialMap.get(asym_id(l)) || 0;
|
||||
return colors[o % colorCount].color;
|
||||
}
|
||||
return defaultColor
|
||||
}
|
||||
return defaultColor;
|
||||
};
|
||||
} else {
|
||||
color = () => defaultColor
|
||||
color = () => defaultColor;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -91,16 +91,16 @@ export function createProteopediaCustomTheme(colors: number[]) {
|
||||
props,
|
||||
description: Description,
|
||||
legend: undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const ProteopediaCustomColorThemeProvider: ColorTheme.Provider<ProteopediaCustomColorThemeParams> = {
|
||||
return {
|
||||
name: 'proteopedia-custom',
|
||||
label: 'Proteopedia Custom',
|
||||
category: 'Custom',
|
||||
factory: ProteopediaCustomColorTheme,
|
||||
getParams: getChainIdColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(ProteopediaCustomColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
|
||||
}
|
||||
|
||||
return ProteopediaCustomColorThemeProvider;
|
||||
};
|
||||
}
|
||||
@@ -4,11 +4,11 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { ResidueIndex, Model } from '../../mol-model/structure';
|
||||
import { BuiltInStructureRepresentationsName } from '../../mol-repr/structure/registry';
|
||||
import { BuiltInColorThemeName } from '../../mol-theme/color';
|
||||
import { AminoAcidNames } from '../../mol-model/structure/model/types';
|
||||
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
|
||||
import { Model, ResidueIndex } from '../../mol-model/structure';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { StructureRepresentationRegistry } from '../../mol-repr/structure/registry';
|
||||
import { ColorTheme } from '../../mol-theme/color';
|
||||
|
||||
export interface ModelInfo {
|
||||
hetResidues: { name: string, indices: ResidueIndex[] }[],
|
||||
@@ -18,9 +18,9 @@ export interface ModelInfo {
|
||||
|
||||
export namespace ModelInfo {
|
||||
async function getPreferredAssembly(ctx: PluginContext, model: Model) {
|
||||
if (model.label.length <= 3) return void 0;
|
||||
if (model.entryId.length <= 3) return void 0;
|
||||
try {
|
||||
const id = model.label.toLowerCase();
|
||||
const id = model.entryId.toLowerCase();
|
||||
const src = await ctx.runTask(ctx.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/${id}` })) as string;
|
||||
const json = JSON.parse(src);
|
||||
const data = json && json[id];
|
||||
@@ -53,14 +53,12 @@ export namespace ModelInfo {
|
||||
const hetMap = new Map<string, ModelInfo['hetResidues'][0]>();
|
||||
|
||||
for (let rI = 0 as ResidueIndex; rI < residueCount; rI++) {
|
||||
const comp_id = model.atomicHierarchy.residues.label_comp_id.value(rI);
|
||||
if (AminoAcidNames.has(comp_id)) continue;
|
||||
const mod_parent = model.properties.modifiedResidues.parentId.get(comp_id);
|
||||
if (mod_parent && AminoAcidNames.has(mod_parent)) continue;
|
||||
|
||||
const cI = chainIndex[residueOffsets[rI]];
|
||||
const eI = model.atomicHierarchy.index.getEntityFromChain(cI);
|
||||
if (model.entities.data.type.value(eI) === 'water') continue;
|
||||
const entityType = model.entities.data.type.value(eI);
|
||||
if (entityType !== 'non-polymer' && entityType !== 'branched') continue;
|
||||
|
||||
const comp_id = model.atomicHierarchy.atoms.label_comp_id.value(residueOffsets[rI]);
|
||||
|
||||
let lig = hetMap.get(comp_id);
|
||||
if (!lig) {
|
||||
@@ -72,10 +70,11 @@ export namespace ModelInfo {
|
||||
}
|
||||
|
||||
const preferredAssemblyId = await pref;
|
||||
const symmetry = ModelSymmetry.Provider.get(model);
|
||||
|
||||
return {
|
||||
hetResidues: hetResidues,
|
||||
assemblies: model.symmetry.assemblies.map(a => ({ id: a.id, details: a.details, isPreferred: a.id === preferredAssemblyId })),
|
||||
assemblies: symmetry ? symmetry.assemblies.map(a => ({ id: a.id, details: a.details, isPreferred: a.id === preferredAssemblyId })) : [],
|
||||
preferredAssemblyId
|
||||
};
|
||||
}
|
||||
@@ -85,6 +84,7 @@ export type SupportedFormats = 'cif' | 'pdb'
|
||||
export interface LoadParams {
|
||||
url: string,
|
||||
format?: SupportedFormats,
|
||||
isBinary?: boolean,
|
||||
assemblyId?: string,
|
||||
representationStyle?: RepresentationStyle
|
||||
}
|
||||
@@ -97,7 +97,7 @@ export interface RepresentationStyle {
|
||||
}
|
||||
|
||||
export namespace RepresentationStyle {
|
||||
export type Entry = { hide?: boolean, kind?: BuiltInStructureRepresentationsName, coloring?: BuiltInColorThemeName }
|
||||
export type Entry = { hide?: boolean, kind?: StructureRepresentationRegistry.BuiltIn, coloring?: ColorTheme.BuiltIn }
|
||||
}
|
||||
|
||||
export enum StateElements {
|
||||
@@ -105,6 +105,8 @@ export enum StateElements {
|
||||
ModelProps = 'model-props',
|
||||
Assembly = 'assembly',
|
||||
|
||||
VolumeStreaming = 'volume-streaming',
|
||||
|
||||
Sequence = 'sequence',
|
||||
SequenceVisual = 'sequence-visual',
|
||||
Het = 'het',
|
||||
@@ -113,5 +115,6 @@ export enum StateElements {
|
||||
Water = 'water',
|
||||
WaterVisual = 'water-visual',
|
||||
|
||||
HetGroupFocus = 'het-group-focus'
|
||||
HetGroupFocus = 'het-group-focus',
|
||||
HetGroupFocusGroup = 'het-group-focus-group'
|
||||
}
|
||||
@@ -40,8 +40,15 @@
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#volume-streaming-wrapper {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 780px;
|
||||
width: 300px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="app.css" />
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
<script type="text/javascript" src="./index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -53,10 +60,12 @@
|
||||
<option value='cif' selected>CIF</option>
|
||||
<option value='pdb'>PDB</option>
|
||||
</select>
|
||||
<input type='checkbox' id='isBinary' style="display: inline-block; width: auto" /> <label for="isBinary"> Binary</label><br />
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
<div id="volume-streaming-wrapper"></div>
|
||||
<script>
|
||||
// it might be a good idea to define these colors in a separate script file
|
||||
// it might be a good idea to define these colors in a separate script file
|
||||
var CustomColors = [0x00ff00, 0x0000ff];
|
||||
|
||||
// create an instance of the plugin
|
||||
@@ -65,24 +74,28 @@
|
||||
console.log('Wrapper version', MolStarProteopediaWrapper.VERSION_MAJOR, MolStarProteopediaWrapper.VERSION_MINOR);
|
||||
|
||||
function $(id) { return document.getElementById(id); }
|
||||
|
||||
var pdbId = '1eve', assemblyId= 'preferred';
|
||||
var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
|
||||
|
||||
var pdbId = '1cbs', assemblyId= 'preferred', isBinary = true;
|
||||
var url = 'https://www.ebi.ac.uk/pdbe/entry-files/download/' + pdbId + '.bcif'
|
||||
var format = 'cif';
|
||||
|
||||
|
||||
$('url').value = url;
|
||||
$('url').onchange = function (e) { url = e.target.value; }
|
||||
$('assemblyId').value = assemblyId;
|
||||
$('assemblyId').onchange = function (e) { assemblyId = e.target.value; }
|
||||
$('format').value = format;
|
||||
$('format').onchange = function (e) { format = e.target.value; }
|
||||
$('isBinary').checked = isBinary;
|
||||
$('isBinary').onchange = function (e) { isBinary = !!e.target.checked; };
|
||||
|
||||
// var url = 'https://www.ebi.ac.uk/pdbe/entry-files/pdb' + pdbId + '.ent';
|
||||
// var format = 'pdb';
|
||||
// var assemblyId = 'deposited';
|
||||
function loadAndSnapshot(params) {
|
||||
PluginWrapper.load(params).then(() => {
|
||||
setTimeout(() => snapshot = PluginWrapper.plugin.state.getSnapshot({ canvas3d: false /* do not save spinning state */ }), 500);
|
||||
});
|
||||
}
|
||||
|
||||
var representationStyle = {
|
||||
sequence: { coloring: 'proteopedia-custom' }, // or just { }
|
||||
// sequence: { coloring: 'proteopedia-custom' }, // or just { }
|
||||
hetGroups: { kind: 'ball-and-stick' }, // or 'spacefill
|
||||
water: { hide: true },
|
||||
snfg3d: { hide: false }
|
||||
@@ -92,7 +105,7 @@
|
||||
customColorList: CustomColors
|
||||
});
|
||||
PluginWrapper.setBackground(0xffffff);
|
||||
PluginWrapper.load({ url: url, format: format, assemblyId: assemblyId, representationStyle: representationStyle });
|
||||
loadAndSnapshot({ url: url, format: format, isBinary: isBinary, assemblyId: assemblyId, representationStyle: representationStyle });
|
||||
PluginWrapper.toggleSpin();
|
||||
|
||||
PluginWrapper.events.modelInfo.subscribe(function (info) {
|
||||
@@ -100,8 +113,8 @@
|
||||
listHetGroups(info);
|
||||
});
|
||||
|
||||
addControl('Load Asym Unit', () => PluginWrapper.load({ url: url, format: format }));
|
||||
addControl('Load Assembly', () => PluginWrapper.load({ url: url, format: format, assemblyId: assemblyId }));
|
||||
addControl('Load Asym Unit', () => loadAndSnapshot({ url: url, format: format, isBinary }));
|
||||
addControl('Load Assembly', () => loadAndSnapshot({ url: url, format: format, isBinary, assemblyId: assemblyId }));
|
||||
|
||||
addSeparator();
|
||||
|
||||
@@ -122,15 +135,19 @@
|
||||
addSeparator();
|
||||
|
||||
addHeader('Camera');
|
||||
addControl('Toggle Spin', () => PluginWrapper.toggleSpin());
|
||||
|
||||
addControl('Reset Position', () => PluginWrapper.camera.resetPosition());
|
||||
addControl('Toggle Spin', () => PluginWrapper.camera.toggleSpin());
|
||||
// Same as "wheel icon" and Viewport options
|
||||
// addControl('Clip', () => PluginWrapper.viewport.setSettings({ clip: [33, 66] }));
|
||||
// addControl('Reset Clip', () => PluginWrapper.viewport.setSettings({ clip: [1, 100] }));
|
||||
|
||||
addSeparator();
|
||||
|
||||
addHeader('Animation');
|
||||
|
||||
// adjust this number to make the animation faster or slower
|
||||
// requires to "restart" the animation if changed
|
||||
PluginWrapper.animate.modelIndex.maxFPS = 30;
|
||||
PluginWrapper.animate.modelIndex.targetFps = 30;
|
||||
|
||||
addControl('Play To End', () => PluginWrapper.animate.modelIndex.onceForward());
|
||||
addControl('Play To Start', () => PluginWrapper.animate.modelIndex.onceBackward());
|
||||
@@ -141,7 +158,8 @@
|
||||
addSeparator();
|
||||
addHeader('Misc');
|
||||
|
||||
addControl('Apply Evo Cons', () => PluginWrapper.coloring.evolutionaryConservation());
|
||||
addControl('Apply Evo Cons Style', () => PluginWrapper.coloring.evolutionaryConservation());
|
||||
addControl('Apply Evo Cons Colors', () => PluginWrapper.coloring.evolutionaryConservation({ sequence: true, het: false, keepStyle: true }));
|
||||
addControl('Default Visuals', () => PluginWrapper.updateStyle());
|
||||
|
||||
addSeparator();
|
||||
@@ -150,20 +168,29 @@
|
||||
addControl('Reset', () => PluginWrapper.hetGroups.reset());
|
||||
addHetGroupsContainer();
|
||||
|
||||
addSeparator();
|
||||
addHeader('Exp. Data');
|
||||
addControl('Init', () => PluginWrapper.experimentalData.init($('volume-streaming-wrapper')));
|
||||
addControl('Remove', () => PluginWrapper.experimentalData.remove());
|
||||
|
||||
addSeparator();
|
||||
addHeader('State');
|
||||
|
||||
var snapshot;
|
||||
addControl('Create Snapshot', () => {
|
||||
snapshot = PluginWrapper.snapshot.get();
|
||||
// could use JSON.stringify(snapshot) and upload the data
|
||||
addControl('Set Snapshot', () => {
|
||||
// const options = { data: true, behavior: false, animation: false, interactivity: false, canvas3d: false, camera: false, cameraTransition: false };
|
||||
snapshot = PluginWrapper.plugin.state.getSnapshot(/** options */);
|
||||
// console.log(JSON.stringify(snapshot, null, 2));
|
||||
});
|
||||
addControl('Apply Snapshot', () => {
|
||||
addControl('Restore Snapshot', () => {
|
||||
if (!snapshot) return;
|
||||
PluginWrapper.snapshot.set(snapshot);
|
||||
|
||||
// or download snapshot using fetch or ajax or whatever
|
||||
// or PluginWrapper.snapshot.download(url);
|
||||
});
|
||||
addControl('Download State', () => {
|
||||
PluginWrapper.snapshot.download('molj');
|
||||
});
|
||||
addControl('Download Session', () => {
|
||||
PluginWrapper.snapshot.download('molx');
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
@@ -199,7 +226,7 @@
|
||||
var l = document.createElement('button');
|
||||
l.innerText = r.name;
|
||||
l.onclick = function () {
|
||||
PluginWrapper.hetGroups.focusFirst(r.name);
|
||||
PluginWrapper.hetGroups.focusFirst(r.name, { doNotLabelWaters: true });
|
||||
};
|
||||
div.appendChild(l);
|
||||
});
|
||||
|
||||
@@ -4,36 +4,36 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
|
||||
import './index.html'
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { PluginCommands } from '../../mol-plugin/command';
|
||||
import { StateTransforms } from '../../mol-plugin/state/transforms';
|
||||
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin/state/objects';
|
||||
import { AnimateModelIndex } from '../../mol-plugin/state/animation/built-in';
|
||||
import { StateBuilder, StateObject } from '../../mol-state';
|
||||
import { EvolutionaryConservation } from './annotation';
|
||||
import { LoadParams, SupportedFormats, RepresentationStyle, ModelInfo, StateElements } from './helpers';
|
||||
import { RxEventHelper } from '../../mol-util/rx-event-helper';
|
||||
import { ControlsWrapper } from './ui/controls';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { Canvas3DProps, DefaultCanvas3DParams } from '../../mol-canvas3d/canvas3d';
|
||||
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
|
||||
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
|
||||
import { PluginStateObject, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { CreateVolumeStreamingInfo, InitVolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { PluginState } from '../../mol-plugin/state';
|
||||
import { Scheduler } from '../../mol-task';
|
||||
import { createProteopediaCustomTheme } from './coloring';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { BuiltInStructureRepresentations } from '../../mol-repr/structure/registry';
|
||||
import { BuiltInColorThemes } from '../../mol-theme/color';
|
||||
import { BuiltInSizeThemes } from '../../mol-theme/size';
|
||||
import { ColorNames } from '../../mol-util/color/tables';
|
||||
// import { Vec3 } from 'mol-math/linear-algebra';
|
||||
// import { ParamDefinition } from 'mol-util/param-definition';
|
||||
// import { Text } from 'mol-geo/geometry/text/text';
|
||||
require('../../mol-plugin/skin/light.scss')
|
||||
import { StateBuilder, StateObject, StateSelection } from '../../mol-state';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { getFormattedTime } from '../../mol-util/date';
|
||||
import { download } from '../../mol-util/download';
|
||||
import { RxEventHelper } from '../../mol-util/rx-event-helper';
|
||||
import { EvolutionaryConservation } from './annotation';
|
||||
import { createProteopediaCustomTheme } from './coloring';
|
||||
import { LoadParams, ModelInfo, RepresentationStyle, StateElements, SupportedFormats } from './helpers';
|
||||
import './index.html';
|
||||
import { volumeStreamingControls } from './ui/controls';
|
||||
require('../../mol-plugin-ui/skin/light.scss');
|
||||
|
||||
class MolStarProteopediaWrapper {
|
||||
static VERSION_MAJOR = 3;
|
||||
static VERSION_MINOR = 1;
|
||||
static VERSION_MAJOR = 5;
|
||||
static VERSION_MINOR = 5;
|
||||
|
||||
private _ev = RxEventHelper.create();
|
||||
|
||||
@@ -41,13 +41,13 @@ class MolStarProteopediaWrapper {
|
||||
modelInfo: this._ev<ModelInfo>()
|
||||
};
|
||||
|
||||
plugin: PluginContext;
|
||||
plugin: PluginUIContext;
|
||||
|
||||
init(target: string | HTMLElement, options?: {
|
||||
customColorList?: number[]
|
||||
}) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginSpec,
|
||||
...DefaultPluginUISpec(),
|
||||
animations: [
|
||||
AnimateModelIndex
|
||||
],
|
||||
@@ -55,30 +55,30 @@ class MolStarProteopediaWrapper {
|
||||
initial: {
|
||||
isExpanded: false,
|
||||
showControls: false
|
||||
},
|
||||
controls: {
|
||||
right: ControlsWrapper
|
||||
}
|
||||
},
|
||||
components: {
|
||||
remoteState: 'none'
|
||||
}
|
||||
});
|
||||
|
||||
const customColoring = createProteopediaCustomTheme((options && options.customColorList) || []);
|
||||
|
||||
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add('proteopedia-custom', customColoring);
|
||||
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(EvolutionaryConservation.Descriptor.name, EvolutionaryConservation.colorTheme!);
|
||||
this.plugin.lociLabels.addProvider(EvolutionaryConservation.labelProvider);
|
||||
this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider);
|
||||
this.plugin.representation.structure.themes.colorThemeRegistry.add(customColoring);
|
||||
this.plugin.representation.structure.themes.colorThemeRegistry.add(EvolutionaryConservation.colorThemeProvider!);
|
||||
this.plugin.managers.lociLabels.addProvider(EvolutionaryConservation.labelProvider!);
|
||||
this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider, true);
|
||||
}
|
||||
|
||||
get state() {
|
||||
return this.plugin.state.dataState;
|
||||
return this.plugin.state.data;
|
||||
}
|
||||
|
||||
private download(b: StateBuilder.To<PSO.Root>, url: string) {
|
||||
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
|
||||
private download(b: StateBuilder.To<PSO.Root>, url: string, isBinary: boolean) {
|
||||
return b.apply(StateTransforms.Data.Download, { url: Asset.Url(url), isBinary });
|
||||
}
|
||||
|
||||
private model(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
|
||||
private model(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats) {
|
||||
const parsed = format === 'cif'
|
||||
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
|
||||
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
|
||||
@@ -89,10 +89,18 @@ class MolStarProteopediaWrapper {
|
||||
|
||||
private structure(assemblyId: string) {
|
||||
const model = this.state.build().to(StateElements.Model);
|
||||
const props = {
|
||||
type: assemblyId ? {
|
||||
name: 'assembly' as const,
|
||||
params: { id: assemblyId }
|
||||
} : {
|
||||
name: 'model' as const,
|
||||
params: { }
|
||||
}
|
||||
};
|
||||
|
||||
const s = model
|
||||
.apply(StateTransforms.Model.CustomModelProperties, { properties: [EvolutionaryConservation.Descriptor.name] }, { ref: StateElements.ModelProps, state: { isGhost: false } })
|
||||
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: StateElements.Assembly });
|
||||
.apply(StateTransforms.Model.StructureFromModel, props, { ref: StateElements.Assembly });
|
||||
|
||||
s.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: StateElements.Sequence });
|
||||
s.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' }, { ref: StateElements.Het });
|
||||
@@ -115,9 +123,10 @@ class MolStarProteopediaWrapper {
|
||||
root.delete(StateElements.SequenceVisual);
|
||||
} else {
|
||||
root.applyOrUpdate(StateElements.SequenceVisual, StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
|
||||
(style.sequence && style.sequence.kind) || 'cartoon',
|
||||
(style.sequence && style.sequence.coloring) || 'unit-index', structure));
|
||||
createStructureRepresentationParams(this.plugin, structure, {
|
||||
type: (style.sequence && style.sequence.kind) || 'cartoon',
|
||||
color: (style.sequence && style.sequence.coloring) || 'unit-index'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,9 +139,10 @@ class MolStarProteopediaWrapper {
|
||||
root.delete(StateElements.HetVisual);
|
||||
} else {
|
||||
root.applyOrUpdate(StateElements.HetVisual, StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
|
||||
(style.hetGroups && style.hetGroups.kind) || 'ball-and-stick',
|
||||
(style.hetGroups && style.hetGroups.coloring), structure));
|
||||
createStructureRepresentationParams(this.plugin, structure, {
|
||||
type: (style.hetGroups && style.hetGroups.kind) || 'ball-and-stick',
|
||||
color: style.hetGroups && style.hetGroups.coloring
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,7 +156,7 @@ class MolStarProteopediaWrapper {
|
||||
root.delete(StateElements.Het3DSNFG);
|
||||
} else {
|
||||
root.applyOrUpdate(StateElements.Het3DSNFG, StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin, 'carbohydrate', void 0, structure));
|
||||
createStructureRepresentationParams(this.plugin, structure, { type: 'carbohydrate' }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,9 +167,11 @@ class MolStarProteopediaWrapper {
|
||||
root.delete(StateElements.WaterVisual);
|
||||
} else {
|
||||
root.applyOrUpdate(StateElements.WaterVisual, StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
|
||||
(style.water && style.water.kind) || 'ball-and-stick',
|
||||
(style.water && style.water.coloring), structure, { alpha: 0.51 }));
|
||||
createStructureRepresentationParams(this.plugin, structure, {
|
||||
type: (style.water && style.water.kind) || 'ball-and-stick',
|
||||
typeParams: { alpha: 0.51 },
|
||||
color: style.water && style.water.coloring
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,20 +189,21 @@ class MolStarProteopediaWrapper {
|
||||
const model = this.getObj<PluginStateObject.Molecule.Model>('model');
|
||||
if (!model) return;
|
||||
|
||||
const info = await ModelInfo.get(this.plugin, model, checkPreferredAssembly)
|
||||
const info = await ModelInfo.get(this.plugin, model, checkPreferredAssembly);
|
||||
this.events.modelInfo.next(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
private applyState(tree: StateBuilder) {
|
||||
return PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
|
||||
return PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
|
||||
}
|
||||
|
||||
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
|
||||
async load({ url, format = 'cif', assemblyId = '', representationStyle }: LoadParams) {
|
||||
private emptyLoadedParams: LoadParams = { url: '', format: 'cif', isBinary: false, assemblyId: '' };
|
||||
private loadedParams: LoadParams = { url: '', format: 'cif', isBinary: false, assemblyId: '' };
|
||||
async load({ url, format = 'cif', assemblyId = '', isBinary = false, representationStyle }: LoadParams) {
|
||||
let loadType: 'full' | 'update' = 'full';
|
||||
|
||||
const state = this.plugin.state.dataState;
|
||||
const state = this.plugin.state.data;
|
||||
|
||||
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
|
||||
loadType = 'full';
|
||||
@@ -199,146 +212,209 @@ class MolStarProteopediaWrapper {
|
||||
}
|
||||
|
||||
if (loadType === 'full') {
|
||||
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
|
||||
const modelTree = this.model(this.download(state.build().toRoot(), url), format, assemblyId);
|
||||
await PluginCommands.State.RemoveObject(this.plugin, { state, ref: state.tree.root.ref });
|
||||
const modelTree = this.model(this.download(state.build().toRoot(), url, isBinary), format);
|
||||
await this.applyState(modelTree);
|
||||
const info = await this.doInfo(true);
|
||||
const structureTree = this.structure((assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId);
|
||||
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
|
||||
const structureTree = this.structure(asmId);
|
||||
await this.applyState(structureTree);
|
||||
} else {
|
||||
const tree = state.build();
|
||||
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
|
||||
const info = await this.doInfo(true);
|
||||
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
|
||||
const props = {
|
||||
type: assemblyId ? {
|
||||
name: 'assembly' as const,
|
||||
params: { id: asmId }
|
||||
} : {
|
||||
name: 'model' as const,
|
||||
params: { }
|
||||
}
|
||||
};
|
||||
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));
|
||||
await this.applyState(tree);
|
||||
}
|
||||
|
||||
await this.updateStyle(representationStyle);
|
||||
|
||||
this.loadedParams = { url, format, assemblyId };
|
||||
Scheduler.setImmediate(() => PluginCommands.Camera.Reset.dispatch(this.plugin, { }));
|
||||
}
|
||||
|
||||
async updateStyle(style?: RepresentationStyle, partial?: boolean) {
|
||||
const tree = this.visual(style, partial);
|
||||
if (!tree) return;
|
||||
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
|
||||
await PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
|
||||
}
|
||||
|
||||
setBackground(color: number) {
|
||||
if (!this.plugin.canvas3d) return;
|
||||
const renderer = this.plugin.canvas3d.props.renderer;
|
||||
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
|
||||
}
|
||||
|
||||
toggleSpin() {
|
||||
if (!this.plugin.canvas3d) return;
|
||||
const trackball = this.plugin.canvas3d.props.trackball;
|
||||
const spinning = trackball.spin;
|
||||
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
|
||||
if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
|
||||
}
|
||||
|
||||
viewport = {
|
||||
setSettings: (settings?: Canvas3DProps) => {
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, {
|
||||
settings: settings || DefaultCanvas3DParams
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
camera = {
|
||||
toggleSpin: () => this.toggleSpin(),
|
||||
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, { })
|
||||
}
|
||||
|
||||
private animateModelIndexTargetFps() {
|
||||
return Math.max(1, this.animate.modelIndex.targetFps | 0);
|
||||
}
|
||||
|
||||
animate = {
|
||||
modelIndex: {
|
||||
maxFPS: 8,
|
||||
onceForward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'forward' } } }) },
|
||||
onceBackward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'backward' } } }) },
|
||||
palindrome: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'palindrome', params: {} } }) },
|
||||
loop: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'loop', params: {} } }) },
|
||||
stop: () => this.plugin.state.animation.stop()
|
||||
targetFps: 8,
|
||||
onceForward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'forward' } } }); },
|
||||
onceBackward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'backward' } } }); },
|
||||
palindrome: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'palindrome', params: {} } }); },
|
||||
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: { direction: 'forward' } } }); },
|
||||
stop: () => this.plugin.managers.animation.stop()
|
||||
}
|
||||
}
|
||||
|
||||
coloring = {
|
||||
evolutionaryConservation: async () => {
|
||||
await this.updateStyle({ sequence: { kind: 'spacefill' } }, true);
|
||||
evolutionaryConservation: async (params?: { sequence?: boolean, het?: boolean, keepStyle?: boolean }) => {
|
||||
if (!params || !params.keepStyle) {
|
||||
await this.updateStyle({ sequence: { kind: 'spacefill' } }, true);
|
||||
}
|
||||
|
||||
const state = this.state;
|
||||
|
||||
// const visuals = state.selectQ(q => q.ofType(PluginStateObject.Molecule.Structure.Representation3D).filter(c => c.transform.transformer === StateTransforms.Representation.StructureRepresentation3D));
|
||||
const tree = state.build();
|
||||
const colorTheme = { name: EvolutionaryConservation.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(EvolutionaryConservation.Descriptor.name).defaultValues };
|
||||
const colorTheme = { name: EvolutionaryConservation.propertyProvider.descriptor.name, params: this.plugin.representation.structure.themes.colorThemeRegistry.get(EvolutionaryConservation.propertyProvider.descriptor.name).defaultValues };
|
||||
|
||||
tree.to(StateElements.SequenceVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
|
||||
// for (const v of visuals) {
|
||||
// }
|
||||
if (!params || !!params.sequence) {
|
||||
tree.to(StateElements.SequenceVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
|
||||
}
|
||||
if (params && !!params.het) {
|
||||
tree.to(StateElements.HetVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
|
||||
}
|
||||
|
||||
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
|
||||
await PluginCommands.State.Update(this.plugin, { state, tree });
|
||||
}
|
||||
}
|
||||
|
||||
private experimentalDataElement?: Element = void 0;
|
||||
experimentalData = {
|
||||
init: async (parent: Element) => {
|
||||
const asm = this.state.select(StateElements.Assembly)[0].obj!;
|
||||
const params = InitVolumeStreaming.createDefaultParams(asm, this.plugin);
|
||||
params.options.behaviorRef = StateElements.VolumeStreaming;
|
||||
params.defaultView = 'box';
|
||||
params.options.channelParams['fo-fc(+ve)'] = { wireframe: true };
|
||||
params.options.channelParams['fo-fc(-ve)'] = { wireframe: true };
|
||||
await this.plugin.runTask(this.state.applyAction(InitVolumeStreaming, params, StateElements.Assembly));
|
||||
this.experimentalDataElement = parent;
|
||||
volumeStreamingControls(this.plugin, parent);
|
||||
},
|
||||
remove: () => {
|
||||
const r = this.state.select(StateSelection.Generators.ofTransformer(CreateVolumeStreamingInfo))[0];
|
||||
if (!r) return;
|
||||
PluginCommands.State.RemoveObject(this.plugin, { state: this.state, ref: r.transform.ref });
|
||||
if (this.experimentalDataElement) {
|
||||
ReactDOM.unmountComponentAtNode(this.experimentalDataElement);
|
||||
this.experimentalDataElement = void 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hetGroups = {
|
||||
reset: () => {
|
||||
const update = this.state.build().delete(StateElements.HetGroupFocus);
|
||||
PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
|
||||
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
|
||||
const update = this.state.build().delete(StateElements.HetGroupFocusGroup);
|
||||
PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
|
||||
PluginCommands.Camera.Reset(this.plugin, { });
|
||||
},
|
||||
focusFirst: async (resn: string) => {
|
||||
focusFirst: async (compId: string, options?: { hideLabels: boolean, doNotLabelWaters: boolean }) => {
|
||||
if (!this.state.transforms.has(StateElements.Assembly)) return;
|
||||
|
||||
// const asm = (this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure).data;
|
||||
await PluginCommands.Camera.Reset(this.plugin, { });
|
||||
|
||||
const update = this.state.build();
|
||||
|
||||
update.delete(StateElements.HetGroupFocus);
|
||||
update.delete(StateElements.HetGroupFocusGroup);
|
||||
|
||||
const surroundings = MS.struct.modifier.includeSurroundings({
|
||||
0: MS.struct.filter.first([
|
||||
MS.struct.generator.atomGroups({
|
||||
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), resn]),
|
||||
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
|
||||
})
|
||||
]),
|
||||
radius: 5,
|
||||
'as-whole-residues': true
|
||||
});
|
||||
const core = MS.struct.filter.first([
|
||||
MS.struct.generator.atomGroups({
|
||||
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), compId]),
|
||||
'group-by': MS.core.str.concat([MS.struct.atomProperty.core.operatorName(), MS.struct.atomProperty.macromolecular.residueKey()])
|
||||
})
|
||||
]);
|
||||
const surroundings = MS.struct.modifier.includeSurroundings({ 0: core, radius: 5, 'as-whole-residues': true });
|
||||
|
||||
const sel = update.to(StateElements.Assembly)
|
||||
.apply(StateTransforms.Model.StructureSelection, { label: resn, query: surroundings }, { ref: StateElements.HetGroupFocus });
|
||||
const group = update.to(StateElements.Assembly).group(StateTransforms.Misc.CreateGroup, { label: compId }, { ref: StateElements.HetGroupFocusGroup });
|
||||
const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
|
||||
const coreSel = group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Core', expression: core }, { ref: StateElements.HetGroupFocus });
|
||||
|
||||
sel.apply(StateTransforms.Representation.StructureRepresentation3D, this.createSurVisualParams());
|
||||
// sel.apply(StateTransforms.Representation.StructureLabels3D, {
|
||||
// target: { name: 'residues', params: { } },
|
||||
// options: {
|
||||
// ...ParamDefinition.getDefaultValues(Text.Params),
|
||||
// background: true,
|
||||
// backgroundMargin: 0.2,
|
||||
// backgroundColor: ColorNames.snow,
|
||||
// backgroundOpacity: 0.9,
|
||||
// }
|
||||
// });
|
||||
|
||||
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
|
||||
coreSel.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
|
||||
type: 'ball-and-stick'
|
||||
}));
|
||||
coreSel.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
|
||||
type: 'label',
|
||||
typeParams: { level: 'element' }
|
||||
}), { tags: ['proteopedia-labels'] });
|
||||
|
||||
group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Surroundings', expression: surroundings })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
|
||||
type: 'ball-and-stick',
|
||||
color: 'uniform', colorParams: { value: ColorNames.gray },
|
||||
size: 'uniform', sizeParams: { value: 0.33 }
|
||||
}));
|
||||
|
||||
if (!options?.hideLabels) {
|
||||
// Labels
|
||||
const waters = MS.struct.generator.atomGroups({
|
||||
'entity-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.entityType(), 'water']),
|
||||
});
|
||||
const exclude = options?.doNotLabelWaters ? MS.struct.combinator.merge([core, waters]) : core;
|
||||
const onlySurroundings = MS.struct.modifier.exceptBy({ 0: surroundings, by: exclude });
|
||||
|
||||
group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Surroundings (only)', expression: onlySurroundings })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
|
||||
type: 'label',
|
||||
typeParams: { level: 'residue' }
|
||||
}), { tags: ['proteopedia-labels'] }); // the tag can later be used to toggle the labels
|
||||
}
|
||||
|
||||
await PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
|
||||
|
||||
const focus = (this.state.select(StateElements.HetGroupFocus)[0].obj as PluginStateObject.Molecule.Structure).data;
|
||||
const sphere = focus.boundary.sphere;
|
||||
// const asmCenter = asm.boundary.sphere.center;
|
||||
// const position = Vec3.sub(Vec3.zero(), sphere.center, asmCenter);
|
||||
// Vec3.normalize(position, position);
|
||||
// Vec3.scaleAndAdd(position, sphere.center, position, sphere.radius);
|
||||
const snapshot = this.plugin.canvas3d.camera.getFocus(sphere.center, 0.75 * sphere.radius);
|
||||
PluginCommands.Camera.SetSnapshot.dispatch(this.plugin, { snapshot, durationMs: 250 });
|
||||
const radius = Math.max(sphere.radius, 5);
|
||||
const snapshot = this.plugin.canvas3d!.camera.getFocus(sphere.center, radius);
|
||||
PluginCommands.Camera.SetSnapshot(this.plugin, { snapshot, durationMs: 250 });
|
||||
}
|
||||
}
|
||||
|
||||
private createSurVisualParams() {
|
||||
const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
|
||||
return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, {
|
||||
repr: BuiltInStructureRepresentations['ball-and-stick'],
|
||||
color: [BuiltInColorThemes.uniform, () => ({ value: ColorNames.gray })],
|
||||
size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )]
|
||||
});
|
||||
}
|
||||
|
||||
snapshot = {
|
||||
get: () => {
|
||||
return this.plugin.state.getSnapshot();
|
||||
get: (params?: PluginState.SnapshotParams) => {
|
||||
return this.plugin.state.getSnapshot(params);
|
||||
},
|
||||
set: (snapshot: PluginState.Snapshot) => {
|
||||
return this.plugin.state.setSnapshot(snapshot);
|
||||
},
|
||||
download: async (url: string) => {
|
||||
download: async (type: 'molj' | 'molx' = 'molj', params?: PluginState.SnapshotParams) => {
|
||||
const data = await this.plugin.managers.snapshot.serialize({ type, params });
|
||||
download(data, `mol-star_state_${getFormattedTime()}.${type}`);
|
||||
},
|
||||
fetch: async (url: string, type: 'molj' | 'molx' = 'molj') => {
|
||||
try {
|
||||
const data = await this.plugin.runTask(this.plugin.fetch({ url }));
|
||||
const snapshot = JSON.parse(data);
|
||||
await this.plugin.state.setSnapshot(snapshot);
|
||||
const data = await this.plugin.runTask(this.plugin.fetch({ url, type: 'binary' }));
|
||||
this.loadedParams = { ...this.emptyLoadedParams };
|
||||
return await this.plugin.managers.snapshot.open(new File([data], `state.${type}`));
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
@@ -4,18 +4,14 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { PluginUIComponent } from '../../../mol-plugin/ui/base';
|
||||
import { CurrentObject } from '../../../mol-plugin/ui/plugin';
|
||||
import { AnimationControls } from '../../../mol-plugin/ui/state/animation';
|
||||
import { CameraSnapshots } from '../../../mol-plugin/ui/camera';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { PluginUIContext } from '../../../mol-plugin-ui/context';
|
||||
import { PluginContextContainer } from '../../../mol-plugin-ui/plugin';
|
||||
import { TransformUpdaterControl } from '../../../mol-plugin-ui/state/update-transform';
|
||||
import { StateElements } from '../helpers';
|
||||
|
||||
export class ControlsWrapper extends PluginUIComponent {
|
||||
render() {
|
||||
return <div className='msp-scrollable-container msp-right-controls'>
|
||||
<CurrentObject />
|
||||
<AnimationControls />
|
||||
<CameraSnapshots />
|
||||
</div>;
|
||||
}
|
||||
export function volumeStreamingControls(plugin: PluginUIContext, parent: Element) {
|
||||
ReactDOM.render(<PluginContextContainer plugin={plugin}>
|
||||
<TransformUpdaterControl nodeRef={StateElements.VolumeStreaming} />
|
||||
</PluginContextContainer>, parent);
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Task, Progress, Scheduler, MultistepTask, chunkedSubtask } from '../mol-task'
|
||||
import { Task, Progress, Scheduler, MultistepTask, chunkedSubtask } from '../mol-task';
|
||||
import { now } from '../mol-util/now';
|
||||
|
||||
export async function test1() {
|
||||
@@ -28,9 +28,9 @@ function messageTree(root: Progress.Node, prefix = ''): string {
|
||||
|
||||
function createTask<T>(delayMs: number, r: T): Task<T> {
|
||||
return Task.create('delayed value ' + r, async ctx => {
|
||||
ctx.update('Processing delayed... ' + r, true);
|
||||
ctx.update(`Processing delayed ${r} after ${delayMs}ms`, true);
|
||||
await Scheduler.delay(delayMs);
|
||||
if (ctx.shouldUpdate) await ctx.update({ message: 'hello from delayed... ' });
|
||||
if (ctx.shouldUpdate) await ctx.update({ message: `hello from delayed ${r} ${delayMs}` });
|
||||
return r;
|
||||
}, () => console.log('On abort called ' + r));
|
||||
}
|
||||
@@ -63,7 +63,7 @@ export function testTree() {
|
||||
const r = await c1 + await c2 + await c3;
|
||||
if (ctx.shouldUpdate) await ctx.update({ message: 'Almost done...' });
|
||||
return r + 1;
|
||||
});
|
||||
}, () => console.log('On abort O'));
|
||||
}
|
||||
|
||||
export type ChunkedState = { i: number, current: number, total: number }
|
||||
@@ -85,19 +85,19 @@ export const ms = MultistepTask('ms-task', ['step 1', 'step 2', 'step 3'], async
|
||||
await step(0);
|
||||
|
||||
const child = Task.create('chunked', async ctx => {
|
||||
const s = await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 125 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p))
|
||||
const s = await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 125 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p));
|
||||
return s.i;
|
||||
});
|
||||
|
||||
await child.runAsChild(ctx);
|
||||
await Scheduler.delay(250);
|
||||
await step(1);
|
||||
await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 80 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p))
|
||||
await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 80 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p));
|
||||
await Scheduler.delay(250);
|
||||
await step(2);
|
||||
await Scheduler.delay(250);
|
||||
return p.i + 3;
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
export function abortingObserver(p: Progress) {
|
||||
@@ -115,7 +115,7 @@ async function test() {
|
||||
// const r = await Run(testTree(), abortingObserver, 250);
|
||||
// console.log(r);
|
||||
|
||||
const m = await ms({ i: 10 }).run(logP);
|
||||
const m = await testTree().run(abortingObserver, 50);
|
||||
console.log(m);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
214
src/extensions/alpha-orbitals/_spec/collocation.spec.ts
Normal file
214
src/extensions/alpha-orbitals/_spec/collocation.spec.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Box3D } from '../../../mol-math/geometry';
|
||||
import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { RuntimeContext } from '../../../mol-task';
|
||||
import { sphericalCollocation } from '../collocation';
|
||||
import { Basis, CubeGridInfo } from '../data-model';
|
||||
|
||||
describe('alpha-orbitals-cubes', () => {
|
||||
it('water', async () => {
|
||||
const grid: CubeGridInfo = {
|
||||
params: {
|
||||
basis: _testBasis,
|
||||
cutoffThreshold: 0,
|
||||
sphericalOrder: 'cca-reverse',
|
||||
boxExpand: 0,
|
||||
gridSpacing: []
|
||||
},
|
||||
box: Box3D.create(Vec3.create(-1, -1, -1), Vec3.create(1, 1, 1)),
|
||||
delta: Vec3.create(2, 2, 2),
|
||||
dimensions: Vec3.create(2, 2, 2),
|
||||
npoints: 8,
|
||||
size: Vec3.create(2, 2, 2)
|
||||
};
|
||||
|
||||
const matrix = await sphericalCollocation(grid, {
|
||||
energy: 0,
|
||||
occupancy: 0,
|
||||
alpha: [-2.2623991420609075e-16, 0.6360205395000592, 0.6672122399886391, -0.3876927909355508, -1.6780131293332933e-16, 2.844782862661151e-16, 4.977960694176068e-19, -2.3945919908996803e-16]
|
||||
}, RuntimeContext.Synchronous);
|
||||
|
||||
const expected = [-0.1451730622877498, 0.06479453956039086, -0.2777738736440713, -0.057116584776260436, 0.05929916178822645, 0.2742903371231049, -0.07221698722165386, 0.15389180241391376];
|
||||
|
||||
expect(matrix.length).toBe(expected.length);
|
||||
|
||||
for (let i = 0; i < matrix.length; i++) {
|
||||
expect(Math.abs(matrix[i] - expected[i]) < 1e-6).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const _testBasis: Basis = {
|
||||
'atoms': [
|
||||
{
|
||||
'center': [
|
||||
0.025886090588624934,
|
||||
0.019164790004065606,
|
||||
-0.013539970104105408
|
||||
] as Vec3,
|
||||
'shells': [
|
||||
{
|
||||
'angularMomentum': [0],
|
||||
'coefficients': [
|
||||
[
|
||||
-0.004151277818987536,
|
||||
-0.02067024147993795,
|
||||
-0.05150303336984537,
|
||||
0.33462711739899537,
|
||||
0.5621061300983125,
|
||||
0.17129946969948573
|
||||
]
|
||||
],
|
||||
'exponents': [
|
||||
152.28769660788095,
|
||||
27.928015215973073,
|
||||
7.848374792384515,
|
||||
1.1223350202705642,
|
||||
0.5093846587907856,
|
||||
0.24292266532510307
|
||||
]
|
||||
},
|
||||
{
|
||||
'angularMomentum': [1],
|
||||
'coefficients': [
|
||||
[
|
||||
0.007924233646294425,
|
||||
0.051441048251911314,
|
||||
0.18984000600705359,
|
||||
0.4049863191150474,
|
||||
0.40123628611490797,
|
||||
0.1051855189039082
|
||||
]
|
||||
],
|
||||
'exponents': [
|
||||
27.203421487167727,
|
||||
7.09409912597673,
|
||||
2.5383362605345954,
|
||||
1.0610730767843852,
|
||||
0.4851948916410433,
|
||||
0.22938302550642545
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'center': [
|
||||
0.5082729578468134,
|
||||
1.6880351220025265,
|
||||
0.4963443067810461
|
||||
] as Vec3,
|
||||
'shells': [
|
||||
{
|
||||
'angularMomentum': [0],
|
||||
'coefficients': [
|
||||
[
|
||||
0.009163596280542963,
|
||||
0.04936149294292479,
|
||||
0.16853830490998634,
|
||||
0.37056279972195677,
|
||||
0.4164915298246781,
|
||||
0.13033408410772263
|
||||
]
|
||||
],
|
||||
'exponents': [
|
||||
33.710073211949485,
|
||||
6.180705022740464,
|
||||
1.7291385346152253,
|
||||
0.5940057549921978,
|
||||
0.2306698170449518,
|
||||
0.09500256906284119
|
||||
]
|
||||
},
|
||||
{
|
||||
'angularMomentum': [0],
|
||||
'coefficients': [
|
||||
[
|
||||
-0.32279868167000036,
|
||||
3.209629817295221,
|
||||
2.4672629224617935,
|
||||
-0.048487066612842224,
|
||||
-0.2611850111200143,
|
||||
-0.8917817597810863,
|
||||
-1.9607480081275706,
|
||||
-2.203769342520311,
|
||||
-0.6896328935259993
|
||||
]
|
||||
],
|
||||
'exponents': [
|
||||
10.256286070314905,
|
||||
0.6227965325875392,
|
||||
0.2391007667853915,
|
||||
33.710073211949485,
|
||||
6.180705022740464,
|
||||
1.7291385346152253,
|
||||
0.5940057549921978,
|
||||
0.2306698170449518,
|
||||
0.09500256906284119
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'center': [
|
||||
1.1367367844436005,
|
||||
-0.47018519422670163,
|
||||
-1.356802622574504
|
||||
] as Vec3,
|
||||
'shells': [
|
||||
{
|
||||
'angularMomentum': [0],
|
||||
'coefficients': [
|
||||
[
|
||||
0.009163596280542963,
|
||||
0.04936149294292479,
|
||||
0.16853830490998634,
|
||||
0.37056279972195677,
|
||||
0.4164915298246781,
|
||||
0.13033408410772263
|
||||
]
|
||||
],
|
||||
'exponents': [
|
||||
33.710073211949485,
|
||||
6.180705022740464,
|
||||
1.7291385346152253,
|
||||
0.5940057549921978,
|
||||
0.2306698170449518,
|
||||
0.09500256906284119
|
||||
]
|
||||
},
|
||||
{
|
||||
'angularMomentum': [0],
|
||||
'coefficients': [
|
||||
[
|
||||
-0.32279868167000036,
|
||||
3.209629817295221,
|
||||
2.4672629224617935,
|
||||
-0.048487066612842224,
|
||||
-0.2611850111200143,
|
||||
-0.8917817597810863,
|
||||
-1.9607480081275706,
|
||||
-2.203769342520311,
|
||||
-0.6896328935259993
|
||||
]
|
||||
],
|
||||
'exponents': [
|
||||
10.256286070314905,
|
||||
0.6227965325875392,
|
||||
0.2391007667853915,
|
||||
33.710073211949485,
|
||||
6.180705022740464,
|
||||
1.7291385346152253,
|
||||
0.5940057549921978,
|
||||
0.2306698170449518,
|
||||
0.09500256906284119
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
162
src/extensions/alpha-orbitals/collocation.ts
Normal file
162
src/extensions/alpha-orbitals/collocation.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Inspired by https://github.com/dgasmith/gau2grid.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { RuntimeContext } from '../../mol-task';
|
||||
import { arrayMin } from '../../mol-util/array';
|
||||
import { AlphaOrbital, CubeGridInfo } from './data-model';
|
||||
import { normalizeBasicOrder, SphericalFunctions } from './spherical-functions';
|
||||
|
||||
export async function sphericalCollocation(
|
||||
grid: CubeGridInfo,
|
||||
orbital: AlphaOrbital,
|
||||
taskCtx: RuntimeContext
|
||||
) {
|
||||
const { basis, sphericalOrder, cutoffThreshold } = grid.params;
|
||||
let baseCount = 0;
|
||||
|
||||
for (const atom of basis.atoms) {
|
||||
for (const shell of atom.shells) {
|
||||
for (const L of shell.angularMomentum) {
|
||||
if (L > 4) {
|
||||
// TODO: will L > 4 be required? Would need to precompute more functions in that case.
|
||||
throw new Error('Angular momentum L > 4 not supported.');
|
||||
}
|
||||
|
||||
baseCount += 2 * L + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const matrix = new Float32Array(grid.npoints);
|
||||
|
||||
let baseIndex = 0;
|
||||
for (const atom of basis.atoms) {
|
||||
for (const shell of atom.shells) {
|
||||
let amIndex = 0;
|
||||
for (const L of shell.angularMomentum) {
|
||||
const alpha = normalizeBasicOrder(
|
||||
L,
|
||||
orbital.alpha.slice(baseIndex, baseIndex + 2 * L + 1),
|
||||
sphericalOrder
|
||||
);
|
||||
baseIndex += 2 * L + 1;
|
||||
|
||||
collocationBasis(
|
||||
matrix,
|
||||
grid,
|
||||
L,
|
||||
shell.coefficients[amIndex++],
|
||||
shell.exponents,
|
||||
atom.center,
|
||||
cutoffThreshold,
|
||||
alpha
|
||||
);
|
||||
|
||||
if (taskCtx.shouldUpdate) {
|
||||
await taskCtx.update({
|
||||
message: 'Computing...',
|
||||
current: baseIndex,
|
||||
max: baseCount,
|
||||
isIndeterminate: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
function collocationBasis(
|
||||
matrix: Float32Array,
|
||||
grid: CubeGridInfo,
|
||||
L: number,
|
||||
coefficients: number[],
|
||||
exponents: number[],
|
||||
center: Vec3,
|
||||
cutoffThreshold: number,
|
||||
alpha: number[]
|
||||
) {
|
||||
const ncoeff = exponents.length;
|
||||
const sphericalFunc = SphericalFunctions[L];
|
||||
|
||||
const cx = center[0],
|
||||
cy = center[1],
|
||||
cz = center[2];
|
||||
const ny = grid.dimensions[1],
|
||||
nz = grid.dimensions[2];
|
||||
const gdx = grid.delta[0],
|
||||
gdy = grid.delta[1],
|
||||
gdz = grid.delta[2];
|
||||
const sx = grid.box.min[0],
|
||||
sy = grid.box.min[1],
|
||||
sz = grid.box.min[2];
|
||||
|
||||
const cutoffRadius =
|
||||
cutoffThreshold > 0
|
||||
? Math.sqrt(-Math.log(cutoffThreshold) / arrayMin(exponents))
|
||||
: 10000;
|
||||
const cutoffSquared = cutoffRadius * cutoffRadius;
|
||||
|
||||
const radiusBox = getRadiusBox(grid, center, cutoffRadius);
|
||||
const iMin = radiusBox[0][0],
|
||||
jMin = radiusBox[0][1],
|
||||
kMin = radiusBox[0][2];
|
||||
const iMax = radiusBox[1][0],
|
||||
jMax = radiusBox[1][1],
|
||||
kMax = radiusBox[1][2];
|
||||
|
||||
for (let i = iMin; i <= iMax; i++) {
|
||||
const x = sx + gdx * i - cx;
|
||||
const oX = i * ny * nz;
|
||||
|
||||
for (let j = jMin; j <= jMax; j++) {
|
||||
const y = sy + gdy * j - cy;
|
||||
const oY = oX + j * nz;
|
||||
for (let k = kMin; k <= kMax; k++) {
|
||||
const z = sz + gdz * k - cz;
|
||||
const R2 = x * x + y * y + z * z;
|
||||
|
||||
if (R2 > cutoffSquared) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let gaussianSum = 0;
|
||||
for (let c = 0; c < ncoeff; c++) {
|
||||
gaussianSum +=
|
||||
coefficients[c] * Math.exp(-exponents[c] * R2);
|
||||
}
|
||||
|
||||
const sphericalSum = L === 0 ? alpha[0] : sphericalFunc(alpha, x, y, z);
|
||||
|
||||
|
||||
matrix[k + oY] += gaussianSum * sphericalSum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRadiusBox(grid: CubeGridInfo, center: Vec3, radius: number) {
|
||||
const r = Vec3.create(radius, radius, radius);
|
||||
const min = Vec3.scaleAndAdd(Vec3(), center, r, -1);
|
||||
const max = Vec3.add(Vec3(), center, r);
|
||||
|
||||
Vec3.sub(min, min, grid.box.min);
|
||||
Vec3.sub(max, max, grid.box.min);
|
||||
|
||||
Vec3.div(min, min, grid.delta);
|
||||
Vec3.floor(min, min);
|
||||
Vec3.max(min, min, Vec3());
|
||||
|
||||
Vec3.div(max, max, grid.delta);
|
||||
Vec3.ceil(max, max);
|
||||
Vec3.min(max, max, Vec3.subScalar(Vec3(), grid.dimensions, 1));
|
||||
|
||||
return [min, max];
|
||||
}
|
||||
143
src/extensions/alpha-orbitals/data-model.ts
Normal file
143
src/extensions/alpha-orbitals/data-model.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Mat4, Tensor, Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { Grid } from '../../mol-model/volume';
|
||||
import { SphericalBasisOrder } from './spherical-functions';
|
||||
import { Box3D, RegularGrid3d } from '../../mol-math/geometry';
|
||||
import { arrayMin, arrayMax, arrayRms, arrayMean } from '../../mol-util/array';
|
||||
import { ModelFormat } from '../../mol-model-formats/format';
|
||||
|
||||
// Note: generally contracted gaussians are currently not supported.
|
||||
export interface SphericalElectronShell {
|
||||
exponents: number[];
|
||||
angularMomentum: number[];
|
||||
// number[] for each angular momentum
|
||||
coefficients: number[][];
|
||||
}
|
||||
|
||||
export interface Basis {
|
||||
atoms: {
|
||||
// in Bohr units!
|
||||
center: Vec3;
|
||||
shells: SphericalElectronShell[];
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface AlphaOrbital {
|
||||
energy: number;
|
||||
occupancy: number;
|
||||
alpha: number[];
|
||||
}
|
||||
|
||||
export interface CubeGridComputationParams {
|
||||
basis: Basis;
|
||||
/**
|
||||
* for each electron shell compute a cutoff radius as
|
||||
* const cutoffRadius = Math.sqrt(-Math.log(cutoffThreshold) / arrayMin(exponents));
|
||||
*/
|
||||
cutoffThreshold: number;
|
||||
sphericalOrder: SphericalBasisOrder;
|
||||
boxExpand: number;
|
||||
gridSpacing: number | [atomCountThreshold: number, spacing: number][];
|
||||
doNotComputeIsovalues?: boolean;
|
||||
}
|
||||
|
||||
export interface CubeGridInfo {
|
||||
params: CubeGridComputationParams;
|
||||
dimensions: Vec3;
|
||||
box: Box3D;
|
||||
size: Vec3;
|
||||
npoints: number;
|
||||
delta: Vec3;
|
||||
}
|
||||
|
||||
export interface CubeGrid {
|
||||
grid: Grid;
|
||||
isovalues?: { negative?: number; positive?: number };
|
||||
}
|
||||
|
||||
export type CubeGridFormat = ModelFormat<CubeGrid>;
|
||||
|
||||
// eslint-disable-next-line
|
||||
export function CubeGridFormat(grid: CubeGrid): CubeGridFormat {
|
||||
return { name: 'custom grid', kind: 'cube-grid', data: grid };
|
||||
}
|
||||
|
||||
export function isCubeGridData(f: ModelFormat): f is CubeGridFormat {
|
||||
return f.kind === 'cube-grid';
|
||||
}
|
||||
|
||||
export function initCubeGrid(params: CubeGridComputationParams): CubeGridInfo {
|
||||
const geometry = params.basis.atoms.map(a => a.center);
|
||||
const { gridSpacing: spacing, boxExpand: expand } = params;
|
||||
|
||||
const count = geometry.length;
|
||||
const box = Box3D.expand(
|
||||
Box3D(),
|
||||
Box3D.fromVec3Array(Box3D(), geometry),
|
||||
Vec3.create(expand, expand, expand)
|
||||
);
|
||||
const size = Box3D.size(Vec3(), box);
|
||||
|
||||
const spacingThresholds =
|
||||
typeof spacing === 'number' ? [[0, spacing]] : [...spacing];
|
||||
spacingThresholds.sort((a, b) => b[0] - a[0]);
|
||||
|
||||
let s = 0.4;
|
||||
for (let i = 0; i <= spacingThresholds.length; i++) {
|
||||
s = spacingThresholds[i][1];
|
||||
if (spacingThresholds[i][0] <= count) break;
|
||||
}
|
||||
|
||||
const dimensions = Vec3.ceil(Vec3(), Vec3.scale(Vec3(), size, 1 / s));
|
||||
|
||||
return {
|
||||
params,
|
||||
box,
|
||||
dimensions,
|
||||
size,
|
||||
npoints: dimensions[0] * dimensions[1] * dimensions[2],
|
||||
delta: Vec3.div(Vec3(), size, Vec3.subScalar(Vec3(), dimensions, 1)),
|
||||
};
|
||||
}
|
||||
|
||||
const BohrToAngstromFactor = 0.529177210859;
|
||||
|
||||
export function createGrid(gridInfo: RegularGrid3d, values: Float32Array, axisOrder: number[]) {
|
||||
const boxSize = Box3D.size(Vec3(), gridInfo.box);
|
||||
const boxOrigin = Vec3.clone(gridInfo.box.min);
|
||||
|
||||
Vec3.scale(boxSize, boxSize, BohrToAngstromFactor);
|
||||
Vec3.scale(boxOrigin, boxOrigin, BohrToAngstromFactor);
|
||||
|
||||
const scale = Mat4.fromScaling(
|
||||
Mat4(),
|
||||
Vec3.div(
|
||||
Vec3(),
|
||||
boxSize,
|
||||
Vec3.sub(Vec3(), gridInfo.dimensions, Vec3.create(1, 1, 1))
|
||||
)
|
||||
);
|
||||
const translate = Mat4.fromTranslation(Mat4(), boxOrigin);
|
||||
const matrix = Mat4.mul(Mat4(), translate, scale);
|
||||
|
||||
const grid: Grid = {
|
||||
transform: { kind: 'matrix', matrix },
|
||||
cells: Tensor.create(
|
||||
Tensor.Space(gridInfo.dimensions, axisOrder, Float32Array),
|
||||
(values as any) as Tensor.Data
|
||||
),
|
||||
stats: {
|
||||
min: arrayMin(values),
|
||||
max: arrayMax(values),
|
||||
mean: arrayMean(values),
|
||||
sigma: arrayRms(values),
|
||||
},
|
||||
};
|
||||
|
||||
return grid;
|
||||
}
|
||||
124
src/extensions/alpha-orbitals/density.ts
Normal file
124
src/extensions/alpha-orbitals/density.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { sortArray } from '../../mol-data/util';
|
||||
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
import { Task } from '../../mol-task';
|
||||
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
|
||||
import { gpuComputeAlphaOrbitalsDensityGridValues } from './gpu/compute';
|
||||
|
||||
export function createSphericalCollocationDensityGrid(
|
||||
params: CubeGridComputationParams, orbitals: AlphaOrbital[], webgl?: WebGLContext
|
||||
): Task<CubeGrid> {
|
||||
return Task.create('Spherical Collocation Grid', async (ctx) => {
|
||||
const cubeGrid = initCubeGrid(params);
|
||||
|
||||
let matrix: Float32Array;
|
||||
if (canComputeGrid3dOnGPU(webgl)) {
|
||||
// console.time('gpu');
|
||||
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl!, cubeGrid, orbitals);
|
||||
// console.timeEnd('gpu');
|
||||
} else {
|
||||
throw new Error('Missing OES_texture_float WebGL extension.');
|
||||
}
|
||||
|
||||
const grid = createGrid(cubeGrid, matrix, [0, 1, 2]);
|
||||
let isovalues: { negative?: number, positive?: number } | undefined;
|
||||
|
||||
if (!params.doNotComputeIsovalues) {
|
||||
isovalues = computeDensityIsocontourValues(matrix, 0.85);
|
||||
}
|
||||
|
||||
return { grid, isovalues };
|
||||
});
|
||||
}
|
||||
|
||||
export function computeDensityIsocontourValues(input: Float32Array, cumulativeThreshold: number) {
|
||||
let weightSum = 0;
|
||||
for (let i = 0, _i = input.length; i < _i; i++) {
|
||||
const v = input[i];
|
||||
const w = Math.abs(v);
|
||||
weightSum += w;
|
||||
}
|
||||
const avgWeight = weightSum / input.length;
|
||||
let minWeight = 3 * avgWeight;
|
||||
|
||||
// do not try to identify isovalues for degenerate data
|
||||
// e.g. all values are almost same
|
||||
if (Math.abs(avgWeight - input[0] * input[0]) < 1e-5) {
|
||||
return { negative: void 0, positive: void 0 };
|
||||
}
|
||||
|
||||
let size = 0;
|
||||
while (true) {
|
||||
let csum = 0;
|
||||
size = 0;
|
||||
for (let i = 0, _i = input.length; i < _i; i++) {
|
||||
const v = input[i];
|
||||
const w = Math.abs(v);
|
||||
if (w >= minWeight) {
|
||||
csum += w;
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
if (csum / weightSum > cumulativeThreshold) {
|
||||
break;
|
||||
}
|
||||
|
||||
minWeight -= avgWeight;
|
||||
}
|
||||
|
||||
const values = new Float32Array(size);
|
||||
const weights = new Float32Array(size);
|
||||
const indices = new Int32Array(size);
|
||||
|
||||
let o = 0;
|
||||
for (let i = 0, _i = input.length; i < _i; i++) {
|
||||
const v = input[i];
|
||||
const w = Math.abs(v);
|
||||
if (w >= minWeight) {
|
||||
values[o] = v;
|
||||
weights[o] = w;
|
||||
indices[o] = o;
|
||||
o++;
|
||||
}
|
||||
}
|
||||
|
||||
sortArray(
|
||||
indices,
|
||||
(indices, i, j) => weights[indices[j]] - weights[indices[i]]
|
||||
);
|
||||
|
||||
let cweight = 0,
|
||||
cutoffIndex = 0;
|
||||
for (let i = 0; i < size; i++) {
|
||||
cweight += weights[indices[i]];
|
||||
|
||||
if (cweight / weightSum >= cumulativeThreshold) {
|
||||
cutoffIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let positive = Number.POSITIVE_INFINITY,
|
||||
negative = Number.NEGATIVE_INFINITY;
|
||||
|
||||
for (let i = 0; i < cutoffIndex; i++) {
|
||||
const v = values[indices[i]];
|
||||
if (v > 0) {
|
||||
if (v < positive) positive = v;
|
||||
} else if (v < 0) {
|
||||
if (v > negative) negative = v;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
negative: negative !== Number.NEGATIVE_INFINITY ? negative : void 0,
|
||||
positive: positive !== Number.POSITIVE_INFINITY ? positive : void 0,
|
||||
};
|
||||
}
|
||||
170
src/extensions/alpha-orbitals/gpu/compute.ts
Normal file
170
src/extensions/alpha-orbitals/gpu/compute.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { createGrid3dComputeRenderable } from '../../../mol-gl/compute/grid3d';
|
||||
import { TextureSpec, UnboxedValues, UniformSpec } from '../../../mol-gl/renderable/schema';
|
||||
import { WebGLContext } from '../../../mol-gl/webgl/context';
|
||||
import { RuntimeContext } from '../../../mol-task';
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { arrayMin } from '../../../mol-util/array';
|
||||
import { AlphaOrbital, Basis, CubeGridInfo } from '../data-model';
|
||||
import { normalizeBasicOrder, SphericalBasisOrder } from '../spherical-functions';
|
||||
import { MAIN, UTILS } from './shader.frag';
|
||||
|
||||
const Schema = {
|
||||
tCenters: TextureSpec('image-float32', 'rgba', 'float', 'nearest'),
|
||||
tInfo: TextureSpec('image-float32', 'rgba', 'float', 'nearest'),
|
||||
tCoeff: TextureSpec('image-float32', 'rgb', 'float', 'nearest'),
|
||||
tAlpha: TextureSpec('image-float32', 'alpha', 'float', 'nearest'),
|
||||
uNCenters: UniformSpec('i'),
|
||||
uNAlpha: UniformSpec('i'),
|
||||
uNCoeff: UniformSpec('i'),
|
||||
uMaxCoeffs: UniformSpec('i'),
|
||||
};
|
||||
|
||||
const Orbitals = createGrid3dComputeRenderable({
|
||||
schema: Schema,
|
||||
loopBounds: ['uNCenters', 'uMaxCoeffs'],
|
||||
mainCode: MAIN,
|
||||
utilCode: UTILS,
|
||||
returnCode: 'v',
|
||||
values(params: { grid: CubeGridInfo, orbital: AlphaOrbital }) {
|
||||
return createTextureData(params.grid, params.orbital);
|
||||
}
|
||||
});
|
||||
|
||||
const Density = createGrid3dComputeRenderable({
|
||||
schema: {
|
||||
...Schema,
|
||||
uOccupancy: UniformSpec('f'),
|
||||
},
|
||||
loopBounds: ['uNCenters', 'uMaxCoeffs'],
|
||||
mainCode: MAIN,
|
||||
utilCode: UTILS,
|
||||
returnCode: 'current + uOccupancy * v * v',
|
||||
values(params: { grid: CubeGridInfo, orbitals: AlphaOrbital[] }) {
|
||||
return {
|
||||
...createTextureData(params.grid, params.orbitals[0]),
|
||||
uOccupancy: 0
|
||||
};
|
||||
},
|
||||
cumulative: {
|
||||
states(params: { grid: CubeGridInfo, orbitals: AlphaOrbital[] }) {
|
||||
return params.orbitals.filter(o => o.occupancy !== 0);
|
||||
},
|
||||
update({ grid }, state: AlphaOrbital, values) {
|
||||
const alpha = getNormalizedAlpha(grid.params.basis, state.alpha, grid.params.sphericalOrder);
|
||||
ValueCell.updateIfChanged(values.uOccupancy, state.occupancy);
|
||||
ValueCell.update(values.tAlpha, { width: alpha.length, height: 1, array: alpha });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export function gpuComputeAlphaOrbitalsGridValues(ctx: RuntimeContext, webgl: WebGLContext, grid: CubeGridInfo, orbital: AlphaOrbital) {
|
||||
return Orbitals(ctx, webgl, grid, { grid, orbital });
|
||||
}
|
||||
|
||||
export function gpuComputeAlphaOrbitalsDensityGridValues(ctx: RuntimeContext, webgl: WebGLContext, grid: CubeGridInfo, orbitals: AlphaOrbital[]) {
|
||||
return Density(ctx, webgl, grid, { grid, orbitals });
|
||||
}
|
||||
|
||||
function getNormalizedAlpha(basis: Basis, alphaOrbitals: number[], sphericalOrder: SphericalBasisOrder) {
|
||||
const alpha = new Float32Array(alphaOrbitals.length);
|
||||
|
||||
let aO = 0;
|
||||
for (const atom of basis.atoms) {
|
||||
for (const shell of atom.shells) {
|
||||
for (const L of shell.angularMomentum) {
|
||||
const a0 = normalizeBasicOrder(L, alphaOrbitals.slice(aO, aO + 2 * L + 1), sphericalOrder);
|
||||
for (let i = 0; i < a0.length; i++) alpha[aO + i] = a0[i];
|
||||
aO += 2 * L + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alpha;
|
||||
}
|
||||
|
||||
function createTextureData(grid: CubeGridInfo, orbital: AlphaOrbital): UnboxedValues<typeof Schema> {
|
||||
const { basis, sphericalOrder, cutoffThreshold } = grid.params;
|
||||
|
||||
let centerCount = 0;
|
||||
let baseCount = 0;
|
||||
let coeffCount = 0;
|
||||
for (const atom of basis.atoms) {
|
||||
for (const shell of atom.shells) {
|
||||
for (const L of shell.angularMomentum) {
|
||||
if (L > 4) {
|
||||
// TODO: will L > 4 be required? Would need to precompute more functions in that case.
|
||||
throw new Error('Angular momentum L > 4 not supported.');
|
||||
}
|
||||
|
||||
centerCount++;
|
||||
baseCount += 2 * L + 1;
|
||||
coeffCount += shell.exponents.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const centers = new Float32Array(4 * centerCount);
|
||||
// L, alpha_offset, coeff_offset_start, coeff_offset_end
|
||||
const info = new Float32Array(4 * centerCount);
|
||||
const alpha = new Float32Array(baseCount);
|
||||
const coeff = new Float32Array(3 * coeffCount);
|
||||
|
||||
let maxCoeffs = 0;
|
||||
let cO = 0, aO = 0, coeffO = 0;
|
||||
for (const atom of basis.atoms) {
|
||||
for (const shell of atom.shells) {
|
||||
|
||||
let amIndex = 0;
|
||||
for (const L of shell.angularMomentum) {
|
||||
const a0 = normalizeBasicOrder(L, orbital.alpha.slice(aO, aO + 2 * L + 1), sphericalOrder);
|
||||
|
||||
const cutoffRadius = cutoffThreshold > 0
|
||||
? Math.sqrt(-Math.log(cutoffThreshold) / arrayMin(shell.exponents))
|
||||
: 10000;
|
||||
|
||||
centers[4 * cO + 0] = atom.center[0];
|
||||
centers[4 * cO + 1] = atom.center[1];
|
||||
centers[4 * cO + 2] = atom.center[2];
|
||||
centers[4 * cO + 3] = cutoffRadius * cutoffRadius;
|
||||
|
||||
info[4 * cO + 0] = L;
|
||||
info[4 * cO + 1] = aO;
|
||||
info[4 * cO + 2] = coeffO;
|
||||
info[4 * cO + 3] = coeffO + shell.exponents.length;
|
||||
|
||||
for (let i = 0; i < a0.length; i++) alpha[aO + i] = a0[i];
|
||||
|
||||
const c0 = shell.coefficients[amIndex++];
|
||||
for (let i = 0; i < shell.exponents.length; i++) {
|
||||
coeff[3 * (coeffO + i) + 0] = c0[i];
|
||||
coeff[3 * (coeffO + i) + 1] = shell.exponents[i];
|
||||
}
|
||||
|
||||
if (c0.length > maxCoeffs) {
|
||||
maxCoeffs = c0.length;
|
||||
}
|
||||
|
||||
cO++;
|
||||
aO += 2 * L + 1;
|
||||
coeffO += shell.exponents.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
uNCenters: centerCount,
|
||||
uNAlpha: baseCount,
|
||||
uNCoeff: coeffCount,
|
||||
uMaxCoeffs: maxCoeffs,
|
||||
tCenters: { width: centerCount, height: 1, array: centers },
|
||||
tInfo: { width: centerCount, height: 1, array: info },
|
||||
tCoeff: { width: coeffCount, height: 1, array: coeff },
|
||||
tAlpha: { width: baseCount, height: 1, array: alpha },
|
||||
};
|
||||
}
|
||||
145
src/extensions/alpha-orbitals/gpu/shader.frag.ts
Normal file
145
src/extensions/alpha-orbitals/gpu/shader.frag.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
export const UTILS = `
|
||||
float L1(vec3 p, float a0, float a1, float a2) {
|
||||
return a0 * p.z + a1 * p.x + a2 * p.y;
|
||||
}
|
||||
|
||||
float L2(vec3 p, float a0, float a1, float a2, float a3, float a4) {
|
||||
float x = p.x, y = p.y, z = p.z;
|
||||
float xx = x * x, yy = y * y, zz = z * z;
|
||||
return (
|
||||
a0 * (-0.5 * xx - 0.5 * yy + zz) +
|
||||
a1 * (1.7320508075688772 * x * z) +
|
||||
a2 * (1.7320508075688772 * y * z) +
|
||||
a3 * (0.8660254037844386 * xx - 0.8660254037844386 * yy) +
|
||||
a4 * (1.7320508075688772 * x * y)
|
||||
);
|
||||
}
|
||||
|
||||
float L3(vec3 p, float a0, float a1, float a2, float a3, float a4, float a5, float a6) {
|
||||
float x = p.x, y = p.y, z = p.z;
|
||||
float xx = x * x, yy = y * y, zz = z * z;
|
||||
float xxx = xx * x, yyy = yy * y, zzz = zz * z;
|
||||
return (
|
||||
a0 * (-1.5 * xx * z - 1.5 * yy * z + zzz) +
|
||||
a1 * (-0.6123724356957945 * xxx - 0.6123724356957945 * x * yy + 2.449489742783178 * x * zz) +
|
||||
a2 * (-0.6123724356957945 * xx * y - 0.6123724356957945 * yyy + 2.449489742783178 * y * zz) +
|
||||
a3 * (1.9364916731037085 * xx * z - 1.9364916731037085 * yy * z) +
|
||||
a4 * (3.872983346207417 * x * y * z) +
|
||||
a5 * (0.7905694150420949 * xxx - 2.3717082451262845 * x * yy) +
|
||||
a6 * (2.3717082451262845 * xx * y - 0.7905694150420949 * yyy)
|
||||
);
|
||||
}
|
||||
|
||||
float L4(vec3 p, float a0, float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8) {
|
||||
float x = p.x, y = p.y, z = p.z;
|
||||
float xx = x * x, yy = y * y, zz = z * z;
|
||||
float xxx = xx * x, yyy = yy * y, zzz = zz * z;
|
||||
float xxxx = xxx * x, yyyy = yyy * y, zzzz = zzz * z;
|
||||
return (
|
||||
a0 * (0.375 * xxxx + 0.75 * xx * yy + 0.375 * yyyy - 3.0 * xx * zz - 3.0 * yy * zz + zzzz) +
|
||||
a1 * (-2.3717082451262845 * xxx * z - 2.3717082451262845 * x * yy * z + 3.1622776601683795 * x * zzz) +
|
||||
a2 * (-2.3717082451262845 * xx * y * z - 2.3717082451262845 * yyy * z + 3.1622776601683795 * y * zzz) +
|
||||
a3 * (-0.5590169943749475 * xxxx + 0.5590169943749475 * yyyy + 3.3541019662496847 * xx * zz - 3.3541019662496847 * yy * zz) +
|
||||
a4 * (-1.118033988749895 * xxx * y - 1.118033988749895 * x * yyy + 6.708203932499369 * x * y * zz) +
|
||||
a5 * (2.091650066335189 * xxx * z + -6.274950199005566 * x * yy * z) +
|
||||
a6 * (6.274950199005566 * xx * y * z + -2.091650066335189 * yyy * z) +
|
||||
a7 * (0.739509972887452 * xxxx - 4.437059837324712 * xx * yy + 0.739509972887452 * yyyy) +
|
||||
a8 * (2.958039891549808 * xxx * y + -2.958039891549808 * x * yyy)
|
||||
);
|
||||
}
|
||||
|
||||
float alpha(float offset, float f) {
|
||||
#ifdef WEBGL1
|
||||
// in webgl1, the value is in the alpha channel!
|
||||
return texture2D(tAlpha, vec2(offset * f, 0.5)).a;
|
||||
#else
|
||||
return texture2D(tAlpha, vec2(offset * f, 0.5)).x;
|
||||
#endif
|
||||
}
|
||||
|
||||
float Y(int L, vec3 X, float aO, float fA) {
|
||||
if (L == 0) {
|
||||
return alpha(aO, fA);
|
||||
} else if (L == 1) {
|
||||
return L1(X,
|
||||
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA)
|
||||
);
|
||||
} else if (L == 2) {
|
||||
return L2(X,
|
||||
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA)
|
||||
);
|
||||
} else if (L == 3) {
|
||||
return L3(X,
|
||||
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA),
|
||||
alpha(aO + 5.0, fA), alpha(aO + 6.0, fA)
|
||||
);
|
||||
} else if (L == 4) {
|
||||
return L4(X,
|
||||
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA),
|
||||
alpha(aO + 5.0, fA), alpha(aO + 6.0, fA), alpha(aO + 7.0, fA), alpha(aO + 8.0, fA)
|
||||
);
|
||||
}
|
||||
// TODO: do we need L > 4?
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
#ifndef WEBGL1
|
||||
float R(float R2, int start, int end, float fCoeff) {
|
||||
float gauss = 0.0;
|
||||
for (int i = start; i < end; i++) {
|
||||
vec2 c = texture2D(tCoeff, vec2(float(i) * fCoeff, 0.5)).xy;
|
||||
gauss += c.x * exp(-c.y * R2);
|
||||
}
|
||||
return gauss;
|
||||
}
|
||||
#else
|
||||
float R(float R2, int start, int end, float fCoeff) {
|
||||
float gauss = 0.0;
|
||||
int o = start;
|
||||
for (int i = 0; i < uMaxCoeffs; i++) {
|
||||
if (o >= end) break;
|
||||
|
||||
vec2 c = texture2D(tCoeff, vec2(float(o) * fCoeff, 0.5)).xy;
|
||||
gauss += c.x * exp(-c.y * R2);
|
||||
o++;
|
||||
}
|
||||
return gauss;
|
||||
}
|
||||
#endif
|
||||
`;
|
||||
|
||||
export const MAIN = `
|
||||
float fCenter = 1.0 / float(uNCenters - 1);
|
||||
float fCoeff = 1.0 / float(uNCoeff - 1);
|
||||
float fA = 1.0 / float(uNAlpha - 1);
|
||||
|
||||
float v = 0.0;
|
||||
|
||||
for (int i = 0; i < uNCenters; i++) {
|
||||
vec2 cCoord = vec2(float(i) * fCenter, 0.5);
|
||||
|
||||
vec4 center = texture2D(tCenters, cCoord);
|
||||
vec3 X = xyz - center.xyz;
|
||||
float R2 = dot(X, X);
|
||||
|
||||
// center.w is squared cutoff radius
|
||||
if (R2 > center.w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec4 info = texture2D(tInfo, cCoord);
|
||||
|
||||
int L = int(info.x);
|
||||
float aO = info.y;
|
||||
int coeffStart = int(info.z);
|
||||
int coeffEnd = int(info.w);
|
||||
|
||||
v += R(R2, coeffStart, coeffEnd, fCoeff) * Y(L, X, aO, fA);
|
||||
}
|
||||
`;
|
||||
131
src/extensions/alpha-orbitals/orbitals.ts
Normal file
131
src/extensions/alpha-orbitals/orbitals.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Inspired by https://github.com/dgasmith/gau2grid.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { sortArray } from '../../mol-data/util';
|
||||
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
import { Task } from '../../mol-task';
|
||||
import { sphericalCollocation } from './collocation';
|
||||
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
|
||||
import { gpuComputeAlphaOrbitalsGridValues } from './gpu/compute';
|
||||
|
||||
// setDebugMode(true);
|
||||
|
||||
export function createSphericalCollocationGrid(
|
||||
params: CubeGridComputationParams, orbital: AlphaOrbital, webgl?: WebGLContext
|
||||
): Task<CubeGrid> {
|
||||
return Task.create('Spherical Collocation Grid', async (ctx) => {
|
||||
const cubeGrid = initCubeGrid(params);
|
||||
|
||||
let matrix: Float32Array;
|
||||
if (canComputeGrid3dOnGPU(webgl)) {
|
||||
// console.time('gpu');
|
||||
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl!, cubeGrid, orbital);
|
||||
// console.timeEnd('gpu');
|
||||
} else {
|
||||
// console.time('cpu');
|
||||
matrix = await sphericalCollocation(cubeGrid, orbital, ctx);
|
||||
// console.timeEnd('cpu');
|
||||
}
|
||||
|
||||
const grid = createGrid(cubeGrid, matrix, [0, 1, 2]);
|
||||
let isovalues: { negative?: number, positive?: number } | undefined;
|
||||
|
||||
if (!params.doNotComputeIsovalues) {
|
||||
isovalues = computeOrbitalIsocontourValues(matrix, 0.85);
|
||||
}
|
||||
|
||||
return { grid, isovalues };
|
||||
});
|
||||
}
|
||||
|
||||
export function computeOrbitalIsocontourValues(input: Float32Array, cumulativeThreshold: number) {
|
||||
let weightSum = 0;
|
||||
for (let i = 0, _i = input.length; i < _i; i++) {
|
||||
const v = input[i];
|
||||
const w = v * v;
|
||||
weightSum += w;
|
||||
}
|
||||
const avgWeight = weightSum / input.length;
|
||||
let minWeight = 3 * avgWeight;
|
||||
|
||||
// do not try to identify isovalues for degenerate data
|
||||
// e.g. all values are almost same
|
||||
if (Math.abs(avgWeight - input[0] * input[0]) < 1e-5) {
|
||||
return { negative: void 0, positive: void 0 };
|
||||
}
|
||||
|
||||
let size = 0;
|
||||
while (true) {
|
||||
let csum = 0;
|
||||
size = 0;
|
||||
for (let i = 0, _i = input.length; i < _i; i++) {
|
||||
const v = input[i];
|
||||
const w = v * v;
|
||||
if (w >= minWeight) {
|
||||
csum += w;
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
if (csum / weightSum > cumulativeThreshold) {
|
||||
break;
|
||||
}
|
||||
|
||||
minWeight -= avgWeight;
|
||||
}
|
||||
|
||||
const values = new Float32Array(size);
|
||||
const weights = new Float32Array(size);
|
||||
const indices = new Int32Array(size);
|
||||
|
||||
let o = 0;
|
||||
for (let i = 0, _i = input.length; i < _i; i++) {
|
||||
const v = input[i];
|
||||
const w = v * v;
|
||||
if (w >= minWeight) {
|
||||
values[o] = v;
|
||||
weights[o] = w;
|
||||
indices[o] = o;
|
||||
o++;
|
||||
}
|
||||
}
|
||||
|
||||
sortArray(
|
||||
indices,
|
||||
(indices, i, j) => weights[indices[j]] - weights[indices[i]]
|
||||
);
|
||||
|
||||
let cweight = 0,
|
||||
cutoffIndex = 0;
|
||||
for (let i = 0; i < size; i++) {
|
||||
cweight += weights[indices[i]];
|
||||
|
||||
if (cweight / weightSum >= cumulativeThreshold) {
|
||||
cutoffIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let positive = Number.POSITIVE_INFINITY,
|
||||
negative = Number.NEGATIVE_INFINITY;
|
||||
|
||||
for (let i = 0; i < cutoffIndex; i++) {
|
||||
const v = values[indices[i]];
|
||||
if (v > 0) {
|
||||
if (v < positive) positive = v;
|
||||
} else if (v < 0) {
|
||||
if (v > negative) negative = v;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
negative: negative !== Number.NEGATIVE_INFINITY ? negative : void 0,
|
||||
positive: positive !== Number.POSITIVE_INFINITY ? positive : void 0,
|
||||
};
|
||||
}
|
||||
93
src/extensions/alpha-orbitals/spherical-functions.ts
Normal file
93
src/extensions/alpha-orbitals/spherical-functions.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Inspired by https://github.com/dgasmith/gau2grid.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
// gaussian:
|
||||
// R_0, R^+_1, R^-_1, ..., R^+_l, R^-_l
|
||||
// cca:
|
||||
// R^-_(l), R^-_(l-1), ..., R_0, ..., R^+_(l-1), R^+_l
|
||||
// cca-reverse:
|
||||
// R^+_(l), R^+_(l-1), ..., R_0, ..., R^-_(l-1), R^-_l
|
||||
export type SphericalBasisOrder = 'gaussian' | 'cca' | 'cca-reverse';
|
||||
|
||||
export function normalizeBasicOrder(
|
||||
L: number,
|
||||
alpha: number[],
|
||||
order: SphericalBasisOrder
|
||||
) {
|
||||
if (order === 'gaussian' || L === 0) return alpha;
|
||||
|
||||
const ret: number[] = [alpha[L]];
|
||||
for (let l = 0; l < L; l++) {
|
||||
const a = alpha[L - l - 1],
|
||||
b = alpha[L + l + 1];
|
||||
if (order === 'cca') ret.push(b, a);
|
||||
else ret.push(a, b);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
export type SphericalFunc = (
|
||||
alpha: number[],
|
||||
x: number,
|
||||
y: number,
|
||||
z: number
|
||||
) => number;
|
||||
|
||||
export const SphericalFunctions: SphericalFunc[] = [L0, L1, L2, L3, L4];
|
||||
|
||||
// L_i functions were auto-generated.
|
||||
|
||||
function L0(alpha: number[], x: number, y: number, z: number) {
|
||||
return alpha[0];
|
||||
}
|
||||
|
||||
function L1(alpha: number[], x: number, y: number, z: number) {
|
||||
return alpha[0] * z + alpha[1] * x + alpha[2] * y;
|
||||
}
|
||||
|
||||
function L2(alpha: number[], x: number, y: number, z: number) {
|
||||
const xx = x * x, yy = y * y, zz = z * z;
|
||||
return (
|
||||
alpha[0] * (-0.5 * xx - 0.5 * yy + zz) +
|
||||
alpha[1] * (1.7320508075688772 * x * z) +
|
||||
alpha[2] * (1.7320508075688772 * y * z) +
|
||||
alpha[3] * (0.8660254037844386 * xx - 0.8660254037844386 * yy) +
|
||||
alpha[4] * (1.7320508075688772 * x * y)
|
||||
);
|
||||
}
|
||||
|
||||
function L3(alpha: number[], x: number, y: number, z: number) {
|
||||
const xx = x * x, yy = y * y, zz = z * z;
|
||||
const xxx = xx * x, yyy = yy * y, zzz = zz * z;
|
||||
return (
|
||||
alpha[0] * (-1.5 * xx * z - 1.5 * yy * z + zzz) +
|
||||
alpha[1] * (-0.6123724356957945 * xxx - 0.6123724356957945 * x * yy + 2.449489742783178 * x * zz) +
|
||||
alpha[2] * (-0.6123724356957945 * xx * y - 0.6123724356957945 * yyy + 2.449489742783178 * y * zz) +
|
||||
alpha[3] * (1.9364916731037085 * xx * z - 1.9364916731037085 * yy * z) +
|
||||
alpha[4] * (3.872983346207417 * x * y * z) +
|
||||
alpha[5] * (0.7905694150420949 * xxx - 2.3717082451262845 * x * yy) +
|
||||
alpha[6] * (2.3717082451262845 * xx * y - 0.7905694150420949 * yyy)
|
||||
);
|
||||
}
|
||||
|
||||
function L4(alpha: number[], x: number, y: number, z: number) {
|
||||
const xx = x * x, yy = y * y, zz = z * z;
|
||||
const xxx = xx * x, yyy = yy * y, zzz = zz * z;
|
||||
const xxxx = xxx * x, yyyy = yyy * y, zzzz = zzz * z;
|
||||
return (
|
||||
alpha[0] * (0.375 * xxxx + 0.75 * xx * yy + 0.375 * yyyy - 3.0 * xx * zz - 3.0 * yy * zz + zzzz) +
|
||||
alpha[1] * (-2.3717082451262845 * xxx * z - 2.3717082451262845 * x * yy * z + 3.1622776601683795 * x * zzz) +
|
||||
alpha[2] * (-2.3717082451262845 * xx * y * z - 2.3717082451262845 * yyy * z + 3.1622776601683795 * y * zzz) +
|
||||
alpha[3] * (-0.5590169943749475 * xxxx + 0.5590169943749475 * yyyy + 3.3541019662496847 * xx * zz - 3.3541019662496847 * yy * zz) +
|
||||
alpha[4] * (-1.118033988749895 * xxx * y - 1.118033988749895 * x * yyy + 6.708203932499369 * x * y * zz) +
|
||||
alpha[5] * (2.091650066335189 * xxx * z + -6.274950199005566 * x * yy * z) +
|
||||
alpha[6] * (6.274950199005566 * xx * y * z + -2.091650066335189 * yyy * z) +
|
||||
alpha[7] * (0.739509972887452 * xxxx - 4.437059837324712 * xx * yy + 0.739509972887452 * yyyy) +
|
||||
alpha[8] * (2.958039891549808 * xxx * y + -2.958039891549808 * x * yyy)
|
||||
);
|
||||
}
|
||||
238
src/extensions/alpha-orbitals/transforms.ts
Normal file
238
src/extensions/alpha-orbitals/transforms.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { PluginStateObject, PluginStateTransform } from '../../mol-plugin-state/objects';
|
||||
import { createSphericalCollocationGrid } from './orbitals';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { Task } from '../../mol-task';
|
||||
import { CustomProperties } from '../../mol-model/custom-property';
|
||||
import { SphericalBasisOrder } from './spherical-functions';
|
||||
import { Volume } from '../../mol-model/volume';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
|
||||
import { StateTransformer } from '../../mol-state';
|
||||
import { Theme } from '../../mol-theme/theme';
|
||||
import { VolumeRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation';
|
||||
import { AlphaOrbital, Basis, CubeGrid, CubeGridFormat, isCubeGridData } from './data-model';
|
||||
import { createSphericalCollocationDensityGrid } from './density';
|
||||
import { Tensor } from '../../mol-math/linear-algebra';
|
||||
|
||||
export class BasisAndOrbitals extends PluginStateObject.Create<{ basis: Basis, order: SphericalBasisOrder, orbitals: AlphaOrbital[] }>({ name: 'Basis', typeClass: 'Object' }) { }
|
||||
|
||||
export const StaticBasisAndOrbitals = PluginStateTransform.BuiltIn({
|
||||
name: 'static-basis-and-orbitals',
|
||||
display: 'Basis and Orbitals',
|
||||
from: PluginStateObject.Root,
|
||||
to: BasisAndOrbitals,
|
||||
params: {
|
||||
label: PD.Text('Orbital Data', { isHidden: true }),
|
||||
basis: PD.Value<Basis>(void 0 as any, { isHidden: true }),
|
||||
order: PD.Text<SphericalBasisOrder>('gaussian' as SphericalBasisOrder, { isHidden: true }),
|
||||
orbitals: PD.Value<AlphaOrbital[]>([], { isHidden: true })
|
||||
},
|
||||
})({
|
||||
apply({ params }) {
|
||||
return new BasisAndOrbitals({ basis: params.basis, order: params.order, orbitals: params.orbitals }, { label: params.label });
|
||||
}
|
||||
});
|
||||
|
||||
const CreateOrbitalVolumeParamBase = {
|
||||
cutoffThreshold: PD.Numeric(0.0015, { min: 0, max: 0.1, step: 0.0001 }),
|
||||
boxExpand: PD.Numeric(4.5, { min: 0, max: 7, step: 0.1 }),
|
||||
gridSpacing: PD.ObjectList({ atomCount: PD.Numeric(0), spacing: PD.Numeric(0.35, { min: 0.1, max: 2, step: 0.01 }) }, e => `Atoms ${e.atomCount}: ${e.spacing}`, {
|
||||
defaultValue: [
|
||||
{ atomCount: 55, spacing: 0.5 },
|
||||
{ atomCount: 40, spacing: 0.45 },
|
||||
{ atomCount: 25, spacing: 0.4 },
|
||||
{ atomCount: 0, spacing: 0.35 },
|
||||
]
|
||||
}),
|
||||
clampValues: PD.MappedStatic('off', {
|
||||
off: PD.EmptyGroup(),
|
||||
on: PD.Group({
|
||||
sigma: PD.Numeric(8, { min: 1, max: 20 }, { description: 'Clamp values to range [sigma * negIsoValue, sigma * posIsoValue].' })
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
function clampData(matrix: Tensor.Data, min: number, max: number) {
|
||||
for (let i = 0, _i = matrix.length; i < _i; i++) {
|
||||
const v = matrix[i];
|
||||
if (v < min) matrix[i] = min;
|
||||
else if (v > max) matrix[i] = max;
|
||||
}
|
||||
}
|
||||
|
||||
function clampGrid(data: CubeGrid, v: number) {
|
||||
const grid = data.grid;
|
||||
const min = (data.isovalues?.negative ?? data.grid.stats.min) * v;
|
||||
const max = (data.isovalues?.positive ?? data.grid.stats.max) * v;
|
||||
|
||||
// clamp values for better direct volume resolution
|
||||
// current implementation uses Byte array for values
|
||||
// if this is not enough, update mol* to use float
|
||||
// textures instead
|
||||
if (grid.stats.min < min || grid.stats.max > max) {
|
||||
clampData(data.grid.cells.data, min, max);
|
||||
if (grid.stats.min < min) {
|
||||
(grid.stats.min as number) = min;
|
||||
}
|
||||
if (grid.stats.max > max) {
|
||||
(grid.stats.max as number) = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const CreateOrbitalVolume = PluginStateTransform.BuiltIn({
|
||||
name: 'create-orbital-volume',
|
||||
display: 'Orbital Volume',
|
||||
from: BasisAndOrbitals,
|
||||
to: PluginStateObject.Volume.Data,
|
||||
params: (a) => {
|
||||
if (!a) {
|
||||
return { index: PD.Numeric(0), ...CreateOrbitalVolumeParamBase };
|
||||
}
|
||||
|
||||
return {
|
||||
index: PD.Select(0, a.data.orbitals.map((o, i) => [i, `[${i + 1}] ${o.energy.toFixed(4)}`])),
|
||||
...CreateOrbitalVolumeParamBase
|
||||
};
|
||||
}
|
||||
})({
|
||||
apply({ a, params }, plugin: PluginContext) {
|
||||
return Task.create('Orbital Volume', async ctx => {
|
||||
const data = await createSphericalCollocationGrid({
|
||||
basis: a.data.basis,
|
||||
cutoffThreshold: params.cutoffThreshold,
|
||||
sphericalOrder: a.data.order,
|
||||
boxExpand: params.boxExpand,
|
||||
gridSpacing: params.gridSpacing.map(e => [e.atomCount, e.spacing] as [number, number])
|
||||
}, a.data.orbitals[params.index], plugin.canvas3d?.webgl).runInContext(ctx);
|
||||
const volume: Volume = {
|
||||
grid: data.grid,
|
||||
sourceData: CubeGridFormat(data),
|
||||
customProperties: new CustomProperties(),
|
||||
_propertyData: Object.create(null),
|
||||
};
|
||||
|
||||
if (params.clampValues?.name === 'on') {
|
||||
clampGrid(data, params.clampValues?.params?.sigma ?? 8);
|
||||
}
|
||||
|
||||
return new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const CreateOrbitalDensityVolume = PluginStateTransform.BuiltIn({
|
||||
name: 'create-orbital-density-volume',
|
||||
display: 'Orbital Density Volume',
|
||||
from: BasisAndOrbitals,
|
||||
to: PluginStateObject.Volume.Data,
|
||||
params: CreateOrbitalVolumeParamBase
|
||||
})({
|
||||
apply({ a, params }, plugin: PluginContext) {
|
||||
return Task.create('Orbital Volume', async ctx => {
|
||||
const data = await createSphericalCollocationDensityGrid({
|
||||
basis: a.data.basis,
|
||||
cutoffThreshold: params.cutoffThreshold,
|
||||
sphericalOrder: a.data.order,
|
||||
boxExpand: params.boxExpand,
|
||||
gridSpacing: params.gridSpacing.map(e => [e.atomCount, e.spacing] as [number, number])
|
||||
}, a.data.orbitals, plugin.canvas3d?.webgl).runInContext(ctx);
|
||||
const volume: Volume = {
|
||||
grid: data.grid,
|
||||
sourceData: CubeGridFormat(data),
|
||||
customProperties: new CustomProperties(),
|
||||
_propertyData: Object.create(null),
|
||||
};
|
||||
|
||||
if (params.clampValues?.name === 'on') {
|
||||
clampGrid(data, params.clampValues?.params?.sigma ?? 8);
|
||||
}
|
||||
|
||||
return new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
|
||||
name: 'create-orbital-representation-3d',
|
||||
display: 'Orbital Representation 3D',
|
||||
from: PluginStateObject.Volume.Data,
|
||||
to: PluginStateObject.Volume.Representation3D,
|
||||
params: {
|
||||
directVolume: PD.Boolean(false),
|
||||
relativeIsovalue: PD.Numeric(1, { min: 0.01, max: 5, step: 0.01 }),
|
||||
kind: PD.Select<'positive' | 'negative'>('positive', [['positive', 'Positive'], ['negative', 'Negative']]),
|
||||
color: PD.Color(ColorNames.blue),
|
||||
alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
|
||||
xrayShaded: PD.Boolean(false),
|
||||
pickable: PD.Boolean(true),
|
||||
tryUseGpu: PD.Boolean(true)
|
||||
}
|
||||
})({
|
||||
canAutoUpdate() {
|
||||
return true;
|
||||
},
|
||||
apply({ a, params: srcParams }, plugin: PluginContext) {
|
||||
return Task.create('Orbitals Representation 3D', async ctx => {
|
||||
const params = volumeParams(plugin, a, srcParams);
|
||||
|
||||
const propertyCtx = { runtime: ctx, assetManager: plugin.managers.asset };
|
||||
const provider = plugin.representation.volume.registry.get(params.type.name);
|
||||
if (provider.ensureCustomProperties) await provider.ensureCustomProperties.attach(propertyCtx, a.data);
|
||||
const props = params.type.params || {};
|
||||
const repr = provider.factory({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.volume.themes }, provider.getParams);
|
||||
repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data }, params));
|
||||
await repr.createOrUpdate(props, a.data).runInContext(ctx);
|
||||
repr.setState({ pickable: srcParams.pickable });
|
||||
return new PluginStateObject.Volume.Representation3D({ repr, sourceData: a.data }, { label: provider.label, description: VolumeRepresentation3DHelpers.getDescription(props) });
|
||||
});
|
||||
},
|
||||
update({ a, b, newParams: srcParams }, plugin: PluginContext) {
|
||||
return Task.create('Orbitals Representation 3D', async ctx => {
|
||||
const newParams = volumeParams(plugin, a, srcParams);
|
||||
|
||||
const props = { ...b.data.repr.props, ...newParams.type.params };
|
||||
b.data.repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data }, newParams));
|
||||
await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
|
||||
b.data.sourceData = a.data;
|
||||
b.data.repr.setState({ pickable: srcParams.pickable });
|
||||
b.description = VolumeRepresentation3DHelpers.getDescription(props);
|
||||
return StateTransformer.UpdateResult.Updated;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function volumeParams(plugin: PluginContext, volume: PluginStateObject.Volume.Data, params: StateTransformer.Params<typeof CreateOrbitalRepresentation3D>) {
|
||||
if (!isCubeGridData(volume.data.sourceData)) throw new Error('Invalid data source kind.');
|
||||
|
||||
const { isovalues } = volume.data.sourceData.data;
|
||||
if (!isovalues) throw new Error('Isovalues are not computed.');
|
||||
|
||||
const value = isovalues[params.kind];
|
||||
|
||||
return createVolumeRepresentationParams(plugin, volume.data, params.directVolume ? {
|
||||
type: 'direct-volume',
|
||||
typeParams: {
|
||||
alpha: params.alpha,
|
||||
renderMode: {
|
||||
name: 'isosurface',
|
||||
params: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, singleLayer: false }
|
||||
},
|
||||
xrayShaded: params.xrayShaded
|
||||
},
|
||||
color: 'uniform',
|
||||
colorParams: { value: params.color }
|
||||
} : {
|
||||
type: 'isosurface',
|
||||
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded, tryUseGpu: params.tryUseGpu },
|
||||
color: 'uniform',
|
||||
colorParams: { value: params.color }
|
||||
});
|
||||
}
|
||||
624
src/extensions/anvil/algorithm.ts
Normal file
624
src/extensions/anvil/algorithm.ts
Normal file
@@ -0,0 +1,624 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Structure, StructureElement, StructureProperties, Unit } from '../../mol-model/structure';
|
||||
import { Task, RuntimeContext } from '../../mol-task';
|
||||
import { CentroidHelper } from '../../mol-math/geometry/centroid-helper';
|
||||
import { AccessibleSurfaceAreaParams } from '../../mol-model-props/computed/accessible-surface-area';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { getElementMoleculeType } from '../../mol-model/structure/util';
|
||||
import { MoleculeType } from '../../mol-model/structure/model/types';
|
||||
import { AccessibleSurfaceArea } from '../../mol-model-props/computed/accessible-surface-area/shrake-rupley';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { MembraneOrientation } from './prop';
|
||||
|
||||
const LARGE_CA_THRESHOLD = 5000;
|
||||
const DEFAULT_UPDATE_INTERVAL = 10;
|
||||
const LARGE_CA_UPDATE_INTERVAL = 1;
|
||||
|
||||
interface ANVILContext {
|
||||
structure: Structure,
|
||||
|
||||
numberOfSpherePoints: number,
|
||||
stepSize: number,
|
||||
minThickness: number,
|
||||
maxThickness: number,
|
||||
asaCutoff: number,
|
||||
adjust: number,
|
||||
|
||||
offsets: ArrayLike<number>,
|
||||
exposed: ArrayLike<number>,
|
||||
hydrophobic: ArrayLike<boolean>,
|
||||
centroid: Vec3,
|
||||
extent: number,
|
||||
large: boolean
|
||||
};
|
||||
|
||||
export const ANVILParams = {
|
||||
numberOfSpherePoints: PD.Numeric(175, { min: 35, max: 700, step: 1 }, { description: 'Number of spheres/directions to test for membrane placement. Original value is 350.' }),
|
||||
stepSize: PD.Numeric(1, { min: 0.25, max: 4, step: 0.25 }, { description: 'Thickness of membrane slices that will be tested' }),
|
||||
minThickness: PD.Numeric(20, { min: 10, max: 30, step: 1 }, { description: 'Minimum membrane thickness used during refinement' }),
|
||||
maxThickness: PD.Numeric(40, { min: 30, max: 50, step: 1 }, { description: 'Maximum membrane thickness used during refinement' }),
|
||||
asaCutoff: PD.Numeric(40, { min: 10, max: 100, step: 1 }, { description: 'Relative ASA cutoff above which residues will be considered' }),
|
||||
adjust: PD.Numeric(14, { min: 0, max: 30, step: 1 }, { description: 'Minimum length of membrane-spanning regions (original values: 14 for alpha-helices and 5 for beta sheets). Set to 0 to not optimize membrane thickness.' }),
|
||||
tmdetDefinition: PD.Boolean(false, { description: `Use TMDET's classification of membrane-favoring amino acids. TMDET's classification shows better performance on porins and other beta-barrel structures.` })
|
||||
};
|
||||
export type ANVILParams = typeof ANVILParams
|
||||
export type ANVILProps = PD.Values<ANVILParams>
|
||||
|
||||
/** ANVIL-specific (not general) definition of membrane-favoring amino acids */
|
||||
const ANVIL_DEFINITION = new Set(['ALA', 'CYS', 'GLY', 'HIS', 'ILE', 'LEU', 'MET', 'PHE', 'SER', 'TRP', 'VAL']);
|
||||
/** TMDET-specific (not general) definition of membrane-favoring amino acids */
|
||||
const TMDET_DEFINITION = new Set(['LEU', 'ILE', 'VAL', 'PHE', 'MET', 'GLY', 'TRP', 'TYR']);
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* Membrane positioning for high- and low-resolution protein structures through a binary classification approach
|
||||
* Guillaume Postic, Yassine Ghouzam, Vincent Guiraud, and Jean-Christophe Gelly
|
||||
* Protein Engineering, Design & Selection, 2015, 1–5
|
||||
* doi: 10.1093/protein/gzv063
|
||||
*
|
||||
* ANVIL is derived from TMDET, the corresponding classification of hydrophobic amino acids is provided as optional parameter:
|
||||
* Gabor E. Tusnady, Zsuzsanna Dosztanyi and Istvan Simon
|
||||
* Transmembrane proteins in the Protein Data Bank: identification and classification
|
||||
* Bioinformatics, 2004, 2964-2972
|
||||
* doi: 10.1093/bioinformatics/bth340
|
||||
*/
|
||||
export function computeANVIL(structure: Structure, props: ANVILProps) {
|
||||
return Task.create('Compute Membrane Orientation', async runtime => {
|
||||
return await calculate(runtime, structure, props);
|
||||
});
|
||||
}
|
||||
|
||||
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
||||
const v3add = Vec3.add;
|
||||
const v3clone = Vec3.clone;
|
||||
const v3create = Vec3.create;
|
||||
const v3distance = Vec3.distance;
|
||||
const v3dot = Vec3.dot;
|
||||
const v3magnitude = Vec3.magnitude;
|
||||
const v3normalize = Vec3.normalize;
|
||||
const v3scale = Vec3.scale;
|
||||
const v3scaleAndAdd = Vec3.scaleAndAdd;
|
||||
const v3set = Vec3.set;
|
||||
const v3squaredDistance = Vec3.squaredDistance;
|
||||
const v3sub = Vec3.sub;
|
||||
const v3zero = Vec3.zero;
|
||||
|
||||
const centroidHelper = new CentroidHelper();
|
||||
async function initialize(structure: Structure, props: ANVILProps, accessibleSurfaceArea: AccessibleSurfaceArea): Promise<ANVILContext> {
|
||||
const l = StructureElement.Location.create(structure);
|
||||
const { label_atom_id, label_comp_id, x, y, z } = StructureProperties.atom;
|
||||
const asaCutoff = props.asaCutoff / 100;
|
||||
centroidHelper.reset();
|
||||
|
||||
const offsets = new Array<number>();
|
||||
const exposed = new Array<number>();
|
||||
const hydrophobic = new Array<boolean>();
|
||||
const definition = props.tmdetDefinition ? TMDET_DEFINITION : ANVIL_DEFINITION;
|
||||
|
||||
function isPartOfEntity(l: StructureElement.Location): boolean {
|
||||
return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.label_seq_id.valueKind(l.unit.residueIndex[l.element]) === 0;
|
||||
}
|
||||
|
||||
const vec = v3zero();
|
||||
for (let i = 0, il = structure.units.length; i < il; ++i) {
|
||||
const unit = structure.units[i];
|
||||
const { elements } = unit;
|
||||
l.unit = unit;
|
||||
|
||||
for (let j = 0, jl = elements.length; j < jl; ++j) {
|
||||
const eI = elements[j];
|
||||
l.element = eI;
|
||||
|
||||
// consider only amino acids in chains
|
||||
if (getElementMoleculeType(unit, eI) !== MoleculeType.Protein || !isPartOfEntity(l)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// only CA is considered for downstream operations
|
||||
if (label_atom_id(l) !== 'CA' && label_atom_id(l) !== 'BB') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// original ANVIL only considers canonical amino acids
|
||||
if (!MaxAsa[label_comp_id(l)]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// while iterating use first pass to compute centroid
|
||||
v3set(vec, x(l), y(l), z(l));
|
||||
centroidHelper.includeStep(vec);
|
||||
|
||||
// keep track of offsets and exposed state to reuse
|
||||
offsets.push(structure.serialMapping.getSerialIndex(l.unit, l.element));
|
||||
if (AccessibleSurfaceArea.getValue(l, accessibleSurfaceArea) / MaxAsa[label_comp_id(l)] > asaCutoff) {
|
||||
exposed.push(structure.serialMapping.getSerialIndex(l.unit, l.element));
|
||||
hydrophobic.push(isHydrophobic(definition, label_comp_id(l)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate centroid and extent
|
||||
centroidHelper.finishedIncludeStep();
|
||||
const centroid = v3clone(centroidHelper.center);
|
||||
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
||||
setLocation(l, structure, offsets[k]);
|
||||
v3set(vec, x(l), y(l), z(l));
|
||||
centroidHelper.radiusStep(vec);
|
||||
}
|
||||
const extent = 1.2 * Math.sqrt(centroidHelper.radiusSq);
|
||||
|
||||
return {
|
||||
...props,
|
||||
structure,
|
||||
|
||||
offsets,
|
||||
exposed,
|
||||
hydrophobic,
|
||||
centroid,
|
||||
extent,
|
||||
large: offsets.length > LARGE_CA_THRESHOLD
|
||||
};
|
||||
}
|
||||
|
||||
export async function calculate(runtime: RuntimeContext, structure: Structure, params: ANVILProps): Promise<MembraneOrientation> {
|
||||
// can't get away with the default 92 points here
|
||||
const asaProps = { ...PD.getDefaultValues(AccessibleSurfaceAreaParams), probeSize: 4.0, traceOnly: true, numberOfSpherePoints: 184 };
|
||||
const accessibleSurfaceArea = await AccessibleSurfaceArea.compute(structure, asaProps).runInContext(runtime);
|
||||
|
||||
const ctx = await initialize(structure, params, accessibleSurfaceArea);
|
||||
const initialHphobHphil = HphobHphil.initial(ctx);
|
||||
|
||||
const initialMembrane = (await findMembrane(runtime, 'Placing initial membrane...', ctx, generateSpherePoints(ctx, ctx.numberOfSpherePoints), initialHphobHphil))!;
|
||||
const refinedMembrane = (await findMembrane(runtime, 'Refining membrane placement...', ctx, findProximateAxes(ctx, initialMembrane), initialHphobHphil))!;
|
||||
let membrane = initialMembrane.qmax! > refinedMembrane.qmax! ? initialMembrane : refinedMembrane;
|
||||
|
||||
if (ctx.adjust && !ctx.large) {
|
||||
membrane = await adjustThickness(runtime, 'Adjusting membrane thickness...', ctx, membrane, initialHphobHphil);
|
||||
}
|
||||
|
||||
const normalVector = v3zero();
|
||||
const center = v3zero();
|
||||
v3sub(normalVector, membrane.planePoint1, membrane.planePoint2);
|
||||
v3normalize(normalVector, normalVector);
|
||||
|
||||
v3add(center, membrane.planePoint1, membrane.planePoint2);
|
||||
v3scale(center, center, 0.5);
|
||||
const extent = adjustExtent(ctx, membrane, center);
|
||||
|
||||
return {
|
||||
planePoint1: membrane.planePoint1,
|
||||
planePoint2: membrane.planePoint2,
|
||||
normalVector,
|
||||
centroid: center,
|
||||
radius: extent
|
||||
};
|
||||
}
|
||||
|
||||
interface MembraneCandidate {
|
||||
planePoint1: Vec3,
|
||||
planePoint2: Vec3,
|
||||
stats: HphobHphil,
|
||||
normalVector?: Vec3,
|
||||
spherePoint?: Vec3,
|
||||
qmax?: number
|
||||
}
|
||||
|
||||
namespace MembraneCandidate {
|
||||
export function initial(c1: Vec3, c2: Vec3, stats: HphobHphil): MembraneCandidate {
|
||||
return {
|
||||
planePoint1: c1,
|
||||
planePoint2: c2,
|
||||
stats
|
||||
};
|
||||
}
|
||||
|
||||
export function scored(spherePoint: Vec3, planePoint1: Vec3, planePoint2: Vec3, stats: HphobHphil, qmax: number, centroid: Vec3): MembraneCandidate {
|
||||
const normalVector = v3zero();
|
||||
v3sub(normalVector, centroid, spherePoint);
|
||||
return {
|
||||
planePoint1,
|
||||
planePoint2,
|
||||
stats,
|
||||
normalVector,
|
||||
spherePoint,
|
||||
qmax
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function findMembrane(runtime: RuntimeContext, message: string | undefined, ctx: ANVILContext, spherePoints: Vec3[], initialStats: HphobHphil): Promise<MembraneCandidate | undefined> {
|
||||
const { centroid, stepSize, minThickness, maxThickness, large } = ctx;
|
||||
// best performing membrane
|
||||
let membrane: MembraneCandidate | undefined;
|
||||
// score of the best performing membrane
|
||||
let qmax = 0;
|
||||
|
||||
// construct slices of thickness 1.0 along the axis connecting the centroid and the spherePoint
|
||||
const diam = v3zero();
|
||||
for (let n = 0, nl = spherePoints.length; n < nl; n++) {
|
||||
if (runtime.shouldUpdate && message && (n + 1) % (large ? LARGE_CA_UPDATE_INTERVAL : DEFAULT_UPDATE_INTERVAL) === 0) {
|
||||
await runtime.update({ message, current: (n + 1), max: nl });
|
||||
}
|
||||
|
||||
const spherePoint = spherePoints[n];
|
||||
v3sub(diam, centroid, spherePoint);
|
||||
v3scale(diam, diam, 2);
|
||||
const diamNorm = v3magnitude(diam);
|
||||
|
||||
const sliceStats = HphobHphil.sliced(ctx, stepSize, spherePoint, diam, diamNorm);
|
||||
const qvartemp = [];
|
||||
for (let i = 0, il = diamNorm - stepSize; i < il; i += stepSize) {
|
||||
const c1 = v3zero();
|
||||
const c2 = v3zero();
|
||||
v3scaleAndAdd(c1, spherePoint, diam, i / diamNorm);
|
||||
v3scaleAndAdd(c2, spherePoint, diam, (i + stepSize) / diamNorm);
|
||||
|
||||
// evaluate how well this membrane slice embeddeds the peculiar residues
|
||||
const stats = sliceStats[Math.round(i / stepSize)];
|
||||
qvartemp.push(MembraneCandidate.initial(c1, c2, stats));
|
||||
}
|
||||
|
||||
let jmax = Math.floor((minThickness / stepSize) - 1);
|
||||
|
||||
for (let width = 0, widthl = maxThickness; width <= widthl;) {
|
||||
for (let i = 0, il = qvartemp.length - 1 - jmax; i < il; i++) {
|
||||
let hphob = 0;
|
||||
let hphil = 0;
|
||||
for (let j = 0; j < jmax; j++) {
|
||||
const ij = qvartemp[i + j];
|
||||
if (j === 0 || j === jmax - 1) {
|
||||
hphob += Math.floor(0.5 * ij.stats.hphob);
|
||||
hphil += 0.5 * ij.stats.hphil;
|
||||
} else {
|
||||
hphob += ij.stats.hphob;
|
||||
hphil += ij.stats.hphil;
|
||||
}
|
||||
}
|
||||
|
||||
if (hphob !== 0) {
|
||||
const stats = { hphob, hphil };
|
||||
const qvaltest = qValue(stats, initialStats);
|
||||
if (qvaltest >= qmax) {
|
||||
qmax = qvaltest;
|
||||
membrane = MembraneCandidate.scored(spherePoint, qvartemp[i].planePoint1, qvartemp[i + jmax].planePoint2, stats, qmax, centroid);
|
||||
}
|
||||
}
|
||||
}
|
||||
jmax++;
|
||||
width = (jmax + 1) * stepSize;
|
||||
}
|
||||
}
|
||||
|
||||
return membrane;
|
||||
}
|
||||
|
||||
/** Adjust membrane thickness by maximizing the number of membrane segments. */
|
||||
async function adjustThickness(runtime: RuntimeContext, message: string | undefined, ctx: ANVILContext, membrane: MembraneCandidate, initialHphobHphil: HphobHphil): Promise<MembraneCandidate> {
|
||||
const { minThickness, large } = ctx;
|
||||
const step = 0.3;
|
||||
let maxThickness = v3distance(membrane.planePoint1, membrane.planePoint2);
|
||||
|
||||
let maxNos = membraneSegments(ctx, membrane).length;
|
||||
let optimalThickness = membrane;
|
||||
|
||||
let n = 0;
|
||||
const nl = Math.ceil((maxThickness - minThickness) / step);
|
||||
while (maxThickness > minThickness) {
|
||||
n++;
|
||||
if (runtime.shouldUpdate && message && n % (large ? LARGE_CA_UPDATE_INTERVAL : DEFAULT_UPDATE_INTERVAL) === 0) {
|
||||
await runtime.update({ message, current: n, max: nl });
|
||||
}
|
||||
|
||||
const p = {
|
||||
...ctx,
|
||||
maxThickness,
|
||||
stepSize: step
|
||||
};
|
||||
const temp = await findMembrane(runtime, void 0, p, [membrane.spherePoint!], initialHphobHphil);
|
||||
if (temp) {
|
||||
const nos = membraneSegments(ctx, temp).length;
|
||||
if (nos > maxNos) {
|
||||
maxNos = nos;
|
||||
optimalThickness = temp;
|
||||
}
|
||||
}
|
||||
maxThickness -= step;
|
||||
}
|
||||
|
||||
return optimalThickness;
|
||||
}
|
||||
|
||||
/** Report auth_seq_ids for all transmembrane segments. Will reject segments that are shorter than the adjust parameter specifies. Missing residues are considered in-membrane. */
|
||||
function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): ArrayLike<{ start: number, end: number }> {
|
||||
const { offsets, structure, adjust } = ctx;
|
||||
const { normalVector, planePoint1, planePoint2 } = membrane;
|
||||
const { units } = structure;
|
||||
const { elementIndices, unitIndices } = structure.serialMapping;
|
||||
const testPoint = v3zero();
|
||||
const { auth_seq_id } = StructureProperties.residue;
|
||||
|
||||
const d1 = -v3dot(normalVector!, planePoint1);
|
||||
const d2 = -v3dot(normalVector!, planePoint2);
|
||||
const dMin = Math.min(d1, d2);
|
||||
const dMax = Math.max(d1, d2);
|
||||
|
||||
const inMembrane: { [k: string]: Set<number> } = Object.create(null);
|
||||
const outMembrane: { [k: string]: Set<number> } = Object.create(null);
|
||||
const segments: Array<{ start: number, end: number }> = [];
|
||||
let authAsymId;
|
||||
let lastAuthAsymId = null;
|
||||
let authSeqId;
|
||||
let lastAuthSeqId = units[0].model.atomicHierarchy.residues.auth_seq_id.value((units[0] as Unit.Atomic).chainIndex[0]) - 1;
|
||||
let startOffset = 0;
|
||||
let endOffset = 0;
|
||||
|
||||
// collect all residues in membrane layer
|
||||
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
||||
const unit = units[unitIndices[offsets[k]]];
|
||||
if (!Unit.isAtomic(unit)) notAtomic();
|
||||
const elementIndex = elementIndices[offsets[k]];
|
||||
|
||||
authAsymId = unit.model.atomicHierarchy.chains.auth_asym_id.value(unit.chainIndex[elementIndex]);
|
||||
if (authAsymId !== lastAuthAsymId) {
|
||||
if (!inMembrane[authAsymId]) inMembrane[authAsymId] = new Set<number>();
|
||||
if (!outMembrane[authAsymId]) outMembrane[authAsymId] = new Set<number>();
|
||||
lastAuthAsymId = authAsymId;
|
||||
}
|
||||
|
||||
authSeqId = unit.model.atomicHierarchy.residues.auth_seq_id.value(unit.residueIndex[elementIndex]);
|
||||
v3set(testPoint, unit.conformation.x(elementIndex), unit.conformation.y(elementIndex), unit.conformation.z(elementIndex));
|
||||
if (_isInMembranePlane(testPoint, normalVector!, dMin, dMax)) {
|
||||
inMembrane[authAsymId].add(authSeqId);
|
||||
} else {
|
||||
outMembrane[authAsymId].add(authSeqId);
|
||||
}
|
||||
}
|
||||
|
||||
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
||||
const unit = units[unitIndices[offsets[k]]];
|
||||
if (!Unit.isAtomic(unit)) notAtomic();
|
||||
const elementIndex = elementIndices[offsets[k]];
|
||||
|
||||
authAsymId = unit.model.atomicHierarchy.chains.auth_asym_id.value(unit.chainIndex[elementIndex]);
|
||||
authSeqId = unit.model.atomicHierarchy.residues.auth_seq_id.value(unit.residueIndex[elementIndex]);
|
||||
if (inMembrane[authAsymId].has(authSeqId)) {
|
||||
// chain change
|
||||
if (authAsymId !== lastAuthAsymId) {
|
||||
segments.push({ start: startOffset, end: endOffset });
|
||||
lastAuthAsymId = authAsymId;
|
||||
startOffset = k;
|
||||
endOffset = k;
|
||||
}
|
||||
|
||||
// sequence gaps
|
||||
if (authSeqId !== lastAuthSeqId + 1) {
|
||||
if (outMembrane[authAsymId].has(lastAuthSeqId + 1)) {
|
||||
segments.push({ start: startOffset, end: endOffset });
|
||||
startOffset = k;
|
||||
}
|
||||
lastAuthSeqId = authSeqId;
|
||||
endOffset = k;
|
||||
} else {
|
||||
lastAuthSeqId++;
|
||||
endOffset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
segments.push({ start: startOffset, end: endOffset });
|
||||
|
||||
const l = StructureElement.Location.create(structure);
|
||||
let startAuth;
|
||||
let endAuth;
|
||||
const refinedSegments: Array<{ start: number, end: number }> = [];
|
||||
for (let k = 0, kl = segments.length; k < kl; k++) {
|
||||
const { start, end } = segments[k];
|
||||
if (start === 0 || end === offsets.length - 1) continue;
|
||||
|
||||
// evaluate residues 1 pos outside of membrane
|
||||
setLocation(l, structure, offsets[start - 1]);
|
||||
v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
||||
const d3 = -v3dot(normalVector!, testPoint);
|
||||
|
||||
setLocation(l, structure, offsets[end + 1]);
|
||||
v3set(testPoint, l.unit.conformation.x(l.element), l.unit.conformation.y(l.element), l.unit.conformation.z(l.element));
|
||||
const d4 = -v3dot(normalVector!, testPoint);
|
||||
|
||||
if (Math.min(d3, d4) < dMin && Math.max(d3, d4) > dMax) {
|
||||
// reject this refinement
|
||||
setLocation(l, structure, offsets[start]);
|
||||
startAuth = auth_seq_id(l);
|
||||
setLocation(l, structure, offsets[end]);
|
||||
endAuth = auth_seq_id(l);
|
||||
if (Math.abs(startAuth - endAuth) + 1 < adjust) {
|
||||
return [];
|
||||
}
|
||||
refinedSegments.push(segments[k]);
|
||||
}
|
||||
}
|
||||
|
||||
return refinedSegments;
|
||||
}
|
||||
|
||||
function notAtomic(): never {
|
||||
throw new Error('Property only available for atomic models.');
|
||||
}
|
||||
|
||||
/** Filter for membrane residues and calculate the final extent of the membrane layer */
|
||||
function adjustExtent(ctx: ANVILContext, membrane: MembraneCandidate, centroid: Vec3): number {
|
||||
const { offsets, structure } = ctx;
|
||||
const { normalVector, planePoint1, planePoint2 } = membrane;
|
||||
const l = StructureElement.Location.create(structure);
|
||||
const testPoint = v3zero();
|
||||
const { x, y, z } = StructureProperties.atom;
|
||||
|
||||
const d1 = -v3dot(normalVector!, planePoint1);
|
||||
const d2 = -v3dot(normalVector!, planePoint2);
|
||||
const dMin = Math.min(d1, d2);
|
||||
const dMax = Math.max(d1, d2);
|
||||
let extent = 0;
|
||||
|
||||
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
||||
setLocation(l, structure, offsets[k]);
|
||||
v3set(testPoint, x(l), y(l), z(l));
|
||||
if (_isInMembranePlane(testPoint, normalVector!, dMin, dMax)) {
|
||||
const dsq = v3squaredDistance(testPoint, centroid);
|
||||
if (dsq > extent) extent = dsq;
|
||||
}
|
||||
}
|
||||
|
||||
return Math.sqrt(extent);
|
||||
}
|
||||
|
||||
function qValue(currentStats: HphobHphil, initialStats: HphobHphil): number {
|
||||
if (initialStats.hphob < 1) {
|
||||
initialStats.hphob = 0.1;
|
||||
}
|
||||
|
||||
if (initialStats.hphil < 1) {
|
||||
initialStats.hphil += 1;
|
||||
}
|
||||
|
||||
const part_tot = currentStats.hphob + currentStats.hphil;
|
||||
return (currentStats.hphob * (initialStats.hphil - currentStats.hphil) - currentStats.hphil * (initialStats.hphob - currentStats.hphob)) /
|
||||
Math.sqrt(part_tot * initialStats.hphob * initialStats.hphil * (initialStats.hphob + initialStats.hphil - part_tot));
|
||||
}
|
||||
|
||||
export function isInMembranePlane(testPoint: Vec3, normalVector: Vec3, planePoint1: Vec3, planePoint2: Vec3): boolean {
|
||||
const d1 = -v3dot(normalVector, planePoint1);
|
||||
const d2 = -v3dot(normalVector, planePoint2);
|
||||
return _isInMembranePlane(testPoint, normalVector, Math.min(d1, d2), Math.max(d1, d2));
|
||||
}
|
||||
|
||||
function _isInMembranePlane(testPoint: Vec3, normalVector: Vec3, min: number, max: number): boolean {
|
||||
const d = -v3dot(normalVector, testPoint);
|
||||
return d > min && d < max;
|
||||
}
|
||||
|
||||
/** Generates a defined number of points on a sphere with radius = extent around the specified centroid */
|
||||
function generateSpherePoints(ctx: ANVILContext, numberOfSpherePoints: number): Vec3[] {
|
||||
const { centroid, extent } = ctx;
|
||||
const points = [];
|
||||
let oldPhi = 0, h, theta, phi;
|
||||
for (let k = 1, kl = numberOfSpherePoints + 1; k < kl; k++) {
|
||||
h = -1 + 2 * (k - 1) / (2 * numberOfSpherePoints - 1);
|
||||
theta = Math.acos(h);
|
||||
phi = (k === 1 || k === numberOfSpherePoints) ? 0 : (oldPhi + 3.6 / Math.sqrt(2 * numberOfSpherePoints * (1 - h * h))) % (2 * Math.PI);
|
||||
|
||||
const point = v3create(
|
||||
extent * Math.sin(phi) * Math.sin(theta) + centroid[0],
|
||||
extent * Math.cos(theta) + centroid[1],
|
||||
extent * Math.cos(phi) * Math.sin(theta) + centroid[2]
|
||||
);
|
||||
points[k - 1] = point;
|
||||
oldPhi = phi;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
/** Generates sphere points close to that of the initial membrane */
|
||||
function findProximateAxes(ctx: ANVILContext, membrane: MembraneCandidate): Vec3[] {
|
||||
const { numberOfSpherePoints, extent } = ctx;
|
||||
const points = generateSpherePoints(ctx, 30000);
|
||||
let j = 4;
|
||||
let sphere_pts2: Vec3[] = [];
|
||||
const s = 2 * extent / numberOfSpherePoints;
|
||||
while (sphere_pts2.length < numberOfSpherePoints) {
|
||||
const dsq = (s + j) * (s + j);
|
||||
sphere_pts2 = [];
|
||||
for (let i = 0, il = points.length; i < il; i++) {
|
||||
if (v3squaredDistance(points[i], membrane.spherePoint!) < dsq) {
|
||||
sphere_pts2.push(points[i]);
|
||||
}
|
||||
}
|
||||
j += 0.2;
|
||||
}
|
||||
return sphere_pts2;
|
||||
}
|
||||
|
||||
interface HphobHphil {
|
||||
hphob: number,
|
||||
hphil: number
|
||||
}
|
||||
|
||||
namespace HphobHphil {
|
||||
export function initial(ctx: ANVILContext): HphobHphil {
|
||||
const { exposed, hydrophobic } = ctx;
|
||||
let hphob = 0;
|
||||
let hphil = 0;
|
||||
for (let k = 0, kl = exposed.length; k < kl; k++) {
|
||||
if (hydrophobic[k]) {
|
||||
hphob++;
|
||||
} else {
|
||||
hphil++;
|
||||
}
|
||||
}
|
||||
return { hphob, hphil };
|
||||
}
|
||||
|
||||
const testPoint = v3zero();
|
||||
export function sliced(ctx: ANVILContext, stepSize: number, spherePoint: Vec3, diam: Vec3, diamNorm: number): HphobHphil[] {
|
||||
const { exposed, hydrophobic, structure } = ctx;
|
||||
const { units, serialMapping } = structure;
|
||||
const { unitIndices, elementIndices } = serialMapping;
|
||||
const sliceStats: HphobHphil[] = [];
|
||||
for (let i = 0, il = diamNorm - stepSize; i < il; i += stepSize) {
|
||||
sliceStats[sliceStats.length] = { hphob: 0, hphil: 0 };
|
||||
}
|
||||
|
||||
for (let i = 0, il = exposed.length; i < il; i++) {
|
||||
const unit = units[unitIndices[exposed[i]]];
|
||||
const elementIndex = elementIndices[exposed[i]];
|
||||
v3set(testPoint, unit.conformation.x(elementIndex), unit.conformation.y(elementIndex), unit.conformation.z(elementIndex));
|
||||
v3sub(testPoint, testPoint, spherePoint);
|
||||
if (hydrophobic[i]) {
|
||||
sliceStats[Math.floor(v3dot(testPoint, diam) / diamNorm / stepSize)].hphob++;
|
||||
} else {
|
||||
sliceStats[Math.floor(v3dot(testPoint, diam) / diamNorm / stepSize)].hphil++;
|
||||
}
|
||||
}
|
||||
return sliceStats;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the definition considers this as membrane-favoring amino acid */
|
||||
export function isHydrophobic(definition: Set<string>, label_comp_id: string): boolean {
|
||||
return definition.has(label_comp_id);
|
||||
}
|
||||
|
||||
/** Accessible surface area used for normalization. ANVIL uses 'Total-Side REL' values from NACCESS, from: Hubbard, S. J., & Thornton, J. M. (1993). naccess. Computer Program, Department of Biochemistry and Molecular Biology, University College London, 2(1). */
|
||||
export const MaxAsa: { [k: string]: number } = {
|
||||
'ALA': 69.41,
|
||||
'ARG': 201.25,
|
||||
'ASN': 106.24,
|
||||
'ASP': 102.69,
|
||||
'CYS': 96.75,
|
||||
'GLU': 134.74,
|
||||
'GLN': 140.99,
|
||||
'GLY': 32.33,
|
||||
'HIS': 147.08,
|
||||
'ILE': 137.96,
|
||||
'LEU': 141.12,
|
||||
'LYS': 163.30,
|
||||
'MET': 156.64,
|
||||
'PHE': 164.11,
|
||||
'PRO': 119.90,
|
||||
'SER': 78.11,
|
||||
'THR': 101.70,
|
||||
'TRP': 211.26,
|
||||
'TYR': 177.38,
|
||||
'VAL': 114.28
|
||||
};
|
||||
|
||||
function setLocation(l: StructureElement.Location, structure: Structure, serialIndex: number) {
|
||||
l.structure = structure;
|
||||
l.unit = structure.units[structure.serialMapping.unitIndices[serialIndex]];
|
||||
l.element = structure.serialMapping.elementIndices[serialIndex];
|
||||
return l;
|
||||
}
|
||||
175
src/extensions/anvil/behavior.ts
Normal file
175
src/extensions/anvil/behavior.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { MembraneOrientationProvider, MembraneOrientation } from './prop';
|
||||
import { StateObjectRef, StateTransformer, StateTransform } from '../../mol-state';
|
||||
import { Task } from '../../mol-task';
|
||||
import { PluginBehavior } from '../../mol-plugin/behavior';
|
||||
import { MembraneOrientationRepresentationProvider, MembraneOrientationParams, MembraneOrientationRepresentation } from './representation';
|
||||
import { HydrophobicityColorThemeProvider } from '../../mol-theme/color/hydrophobicity';
|
||||
import { PluginStateObject, PluginStateTransform } from '../../mol-plugin-state/objects';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { DefaultQueryRuntimeTable } from '../../mol-script/runtime/query/compiler';
|
||||
import { StructureSelectionQuery, StructureSelectionCategory } from '../../mol-plugin-state/helpers/structure-selection-query';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { GenericRepresentationRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
|
||||
|
||||
const Tag = MembraneOrientation.Tag;
|
||||
|
||||
export const ANVILMembraneOrientation = PluginBehavior.create<{ autoAttach: boolean }>({
|
||||
name: 'anvil-membrane-orientation-prop',
|
||||
category: 'custom-props',
|
||||
display: {
|
||||
name: 'Membrane Orientation',
|
||||
description: 'Data calculated with ANVIL algorithm.'
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
|
||||
private provider = MembraneOrientationProvider
|
||||
|
||||
register(): void {
|
||||
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
|
||||
|
||||
this.ctx.customStructureProperties.register(this.provider, this.params.autoAttach);
|
||||
|
||||
this.ctx.representation.structure.registry.add(MembraneOrientationRepresentationProvider);
|
||||
this.ctx.query.structure.registry.add(isTransmembrane);
|
||||
|
||||
this.ctx.genericRepresentationControls.set(Tag.Representation, selection => {
|
||||
const refs: GenericRepresentationRef[] = [];
|
||||
selection.structures.forEach(structure => {
|
||||
const memRepr = structure.genericRepresentations?.filter(r => r.cell.transform.transformer.id === MembraneOrientation3D.id)[0];
|
||||
if (memRepr) refs.push(memRepr);
|
||||
});
|
||||
return [refs, 'Membrane Orientation'];
|
||||
});
|
||||
this.ctx.builders.structure.representation.registerPreset(MembraneOrientationPreset);
|
||||
}
|
||||
|
||||
update(p: { autoAttach: boolean }) {
|
||||
const updated = this.params.autoAttach !== p.autoAttach;
|
||||
this.params.autoAttach = p.autoAttach;
|
||||
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
|
||||
return updated;
|
||||
}
|
||||
|
||||
unregister() {
|
||||
DefaultQueryRuntimeTable.removeCustomProp(this.provider.descriptor);
|
||||
|
||||
this.ctx.customStructureProperties.unregister(this.provider.descriptor.name);
|
||||
|
||||
this.ctx.representation.structure.registry.remove(MembraneOrientationRepresentationProvider);
|
||||
this.ctx.query.structure.registry.remove(isTransmembrane);
|
||||
|
||||
this.ctx.genericRepresentationControls.delete(Tag.Representation);
|
||||
this.ctx.builders.structure.representation.unregisterPreset(MembraneOrientationPreset);
|
||||
}
|
||||
},
|
||||
params: () => ({
|
||||
autoAttach: PD.Boolean(false)
|
||||
})
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
export const isTransmembrane = StructureSelectionQuery('Residues Embedded in Membrane', MS.struct.modifier.union([
|
||||
MS.struct.modifier.wholeResidues([
|
||||
MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'atom-test': MembraneOrientation.symbols.isTransmembrane.symbol(),
|
||||
})
|
||||
])
|
||||
])
|
||||
]), {
|
||||
description: 'Select residues that are embedded between the membrane layers.',
|
||||
category: StructureSelectionCategory.Residue,
|
||||
ensureCustomProperties: (ctx, structure) => {
|
||||
return MembraneOrientationProvider.attach(ctx, structure);
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
export { MembraneOrientation3D };
|
||||
|
||||
type MembraneOrientation3D = typeof MembraneOrientation3D
|
||||
const MembraneOrientation3D = PluginStateTransform.BuiltIn({
|
||||
name: 'membrane-orientation-3d',
|
||||
display: {
|
||||
name: 'Membrane Orientation',
|
||||
description: 'Membrane Orientation planes and rims. Data calculated with ANVIL algorithm.'
|
||||
},
|
||||
from: PluginStateObject.Molecule.Structure,
|
||||
to: PluginStateObject.Shape.Representation3D,
|
||||
params: (a) => {
|
||||
return {
|
||||
...MembraneOrientationParams,
|
||||
};
|
||||
}
|
||||
})({
|
||||
canAutoUpdate({ oldParams, newParams }) {
|
||||
return true;
|
||||
},
|
||||
apply({ a, params }, plugin: PluginContext) {
|
||||
return Task.create('Membrane Orientation', async ctx => {
|
||||
await MembraneOrientationProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, a.data);
|
||||
const repr = MembraneOrientationRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => MembraneOrientationParams);
|
||||
await repr.createOrUpdate(params, a.data).runInContext(ctx);
|
||||
return new PluginStateObject.Shape.Representation3D({ repr, sourceData: a.data }, { label: 'Membrane Orientation' });
|
||||
});
|
||||
},
|
||||
update({ a, b, newParams }, plugin: PluginContext) {
|
||||
return Task.create('Membrane Orientation', async ctx => {
|
||||
await MembraneOrientationProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, a.data);
|
||||
const props = { ...b.data.repr.props, ...newParams };
|
||||
await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
|
||||
b.data.sourceData = a.data;
|
||||
return StateTransformer.UpdateResult.Updated;
|
||||
});
|
||||
},
|
||||
isApplicable(a) {
|
||||
return MembraneOrientationProvider.isApplicable(a.data);
|
||||
}
|
||||
});
|
||||
|
||||
export const MembraneOrientationPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-membrane-orientation',
|
||||
display: {
|
||||
name: 'Membrane Orientation', group: 'Annotation',
|
||||
description: 'Shows orientation of membrane layers. Data calculated with ANVIL algorithm.' // TODO add ' or obtained via RCSB PDB'
|
||||
},
|
||||
isApplicable(a) {
|
||||
return MembraneOrientationProvider.isApplicable(a.data);
|
||||
},
|
||||
params: () => StructureRepresentationPresetProvider.CommonParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
if (!MembraneOrientationProvider.get(structure).value) {
|
||||
await plugin.runTask(Task.create('Membrane Orientation', async runtime => {
|
||||
await MembraneOrientationProvider.attach({ runtime, assetManager: plugin.managers.asset }, structure);
|
||||
}));
|
||||
}
|
||||
|
||||
const membraneOrientation = await tryCreateMembraneOrientation(plugin, structureCell);
|
||||
const colorTheme = HydrophobicityColorThemeProvider.name as any;
|
||||
const preset = await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
|
||||
|
||||
return { components: preset.components, representations: { ...preset.representations, membraneOrientation } };
|
||||
}
|
||||
});
|
||||
|
||||
export function tryCreateMembraneOrientation(plugin: PluginContext, structure: StateObjectRef<PluginStateObject.Molecule.Structure>, params?: StateTransformer.Params<MembraneOrientation3D>, initialState?: Partial<StateTransform.State>) {
|
||||
const state = plugin.state.data;
|
||||
const membraneOrientation = state.build().to(structure)
|
||||
.applyOrUpdateTagged('membrane-orientation-3d', MembraneOrientation3D, params, { state: initialState });
|
||||
return membraneOrientation.commit({ revertOnError: true });
|
||||
}
|
||||
80
src/extensions/anvil/prop.ts
Normal file
80
src/extensions/anvil/prop.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { Structure, StructureProperties, Unit } from '../../mol-model/structure';
|
||||
import { CustomPropertyDescriptor } from '../../mol-model/custom-property';
|
||||
import { ANVILParams, ANVILProps, computeANVIL, isInMembranePlane } from './algorithm';
|
||||
import { CustomStructureProperty } from '../../mol-model-props/common/custom-structure-property';
|
||||
import { CustomProperty } from '../../mol-model-props/common/custom-property';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { QuerySymbolRuntime } from '../../mol-script/runtime/query/base';
|
||||
import { CustomPropSymbol } from '../../mol-script/language/symbol';
|
||||
import { Type } from '../../mol-script/language/type';
|
||||
|
||||
export const MembraneOrientationParams = {
|
||||
...ANVILParams
|
||||
};
|
||||
export type MembraneOrientationParams = typeof MembraneOrientationParams
|
||||
export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
|
||||
|
||||
export { MembraneOrientation };
|
||||
|
||||
interface MembraneOrientation {
|
||||
// point in membrane boundary
|
||||
readonly planePoint1: Vec3,
|
||||
// point in opposite side of membrane boundary
|
||||
readonly planePoint2: Vec3,
|
||||
// normal vector of membrane layer
|
||||
readonly normalVector: Vec3,
|
||||
// the radius of the membrane layer
|
||||
readonly radius: number,
|
||||
readonly centroid: Vec3
|
||||
}
|
||||
|
||||
namespace MembraneOrientation {
|
||||
export enum Tag {
|
||||
Representation = 'membrane-orientation-3d'
|
||||
}
|
||||
|
||||
const pos = Vec3();
|
||||
export const symbols = {
|
||||
isTransmembrane: QuerySymbolRuntime.Dynamic(CustomPropSymbol('computed', 'membrane-orientation.is-transmembrane', Type.Bool),
|
||||
ctx => {
|
||||
const { unit, structure } = ctx.element;
|
||||
const { x, y, z } = StructureProperties.atom;
|
||||
if (!Unit.isAtomic(unit)) return 0;
|
||||
const membraneOrientation = MembraneOrientationProvider.get(structure).value;
|
||||
if (!membraneOrientation) return 0;
|
||||
Vec3.set(pos, x(ctx.element), y(ctx.element), z(ctx.element));
|
||||
const { normalVector, planePoint1, planePoint2 } = membraneOrientation!;
|
||||
return isInMembranePlane(pos, normalVector, planePoint1, planePoint2);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
export const MembraneOrientationProvider: CustomStructureProperty.Provider<MembraneOrientationParams, MembraneOrientation> = CustomStructureProperty.createProvider({
|
||||
label: 'Membrane Orientation',
|
||||
descriptor: CustomPropertyDescriptor({
|
||||
name: 'anvil_computed_membrane_orientation',
|
||||
symbols: MembraneOrientation.symbols,
|
||||
// TODO `cifExport`
|
||||
}),
|
||||
type: 'root',
|
||||
defaultParams: MembraneOrientationParams,
|
||||
getParams: (data: Structure) => MembraneOrientationParams,
|
||||
isApplicable: (data: Structure) => true,
|
||||
obtain: async (ctx: CustomProperty.Context, data: Structure, props: Partial<MembraneOrientationProps>) => {
|
||||
const p = { ...PD.getDefaultValues(MembraneOrientationParams), ...props };
|
||||
return { value: await computeAnvil(ctx, data, p) };
|
||||
}
|
||||
});
|
||||
|
||||
async function computeAnvil(ctx: CustomProperty.Context, data: Structure, props: Partial<ANVILProps>): Promise<MembraneOrientation> {
|
||||
const p = { ...PD.getDefaultValues(ANVILParams), ...props };
|
||||
return await computeANVIL(data, p).runInContext(ctx.runtime);
|
||||
}
|
||||
150
src/extensions/anvil/representation.ts
Normal file
150
src/extensions/anvil/representation.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
|
||||
import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../mol-repr/representation';
|
||||
import { Structure } from '../../mol-model/structure';
|
||||
import { StructureRepresentationProvider, StructureRepresentation, StructureRepresentationStateBuilder } from '../../mol-repr/structure/representation';
|
||||
import { MembraneOrientation } from './prop';
|
||||
import { ThemeRegistryContext } from '../../mol-theme/theme';
|
||||
import { ShapeRepresentation } from '../../mol-repr/shape/representation';
|
||||
import { Shape } from '../../mol-model/shape';
|
||||
import { RuntimeContext } from '../../mol-task';
|
||||
import { Lines } from '../../mol-geo/geometry/lines/lines';
|
||||
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
|
||||
import { LinesBuilder } from '../../mol-geo/geometry/lines/lines-builder';
|
||||
import { Circle } from '../../mol-geo/primitive/circle';
|
||||
import { transformPrimitive } from '../../mol-geo/primitive/primitive';
|
||||
import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
|
||||
import { MembraneOrientationProvider } from './prop';
|
||||
import { MarkerActions } from '../../mol-util/marker-action';
|
||||
import { lociLabel } from '../../mol-theme/label';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { CustomProperty } from '../../mol-model-props/common/custom-property';
|
||||
|
||||
const SharedParams = {
|
||||
color: PD.Color(ColorNames.lightgrey),
|
||||
radiusFactor: PD.Numeric(1.2, { min: 0.1, max: 3.0, step: 0.01 }, { description: 'Scale the radius of the membrane layer' })
|
||||
};
|
||||
|
||||
const BilayerPlanesParams = {
|
||||
...Mesh.Params,
|
||||
...SharedParams,
|
||||
sectorOpacity: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
|
||||
};
|
||||
export type BilayerPlanesParams = typeof BilayerPlanesParams
|
||||
export type BilayerPlanesProps = PD.Values<BilayerPlanesParams>
|
||||
|
||||
const BilayerRimsParams = {
|
||||
...Lines.Params,
|
||||
...SharedParams,
|
||||
lineSizeAttenuation: PD.Boolean(true),
|
||||
linesSize: PD.Numeric(0.3, { min: 0.01, max: 50, step: 0.01 }),
|
||||
dashedLines: PD.Boolean(true),
|
||||
};
|
||||
export type BilayerRimsParams = typeof BilayerRimsParams
|
||||
export type BilayerRimsProps = PD.Values<BilayerRimsParams>
|
||||
|
||||
const MembraneOrientationVisuals = {
|
||||
'bilayer-planes': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerPlanesParams>) => ShapeRepresentation(getBilayerPlanes, Mesh.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }), modifyProps: p => ({ ...p, alpha: p.sectorOpacity, ignoreLight: true, doubleSided: false }) }),
|
||||
'bilayer-rims': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerRimsParams>) => ShapeRepresentation(getBilayerRims, Lines.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }) })
|
||||
};
|
||||
|
||||
export const MembraneOrientationParams = {
|
||||
...BilayerPlanesParams,
|
||||
...BilayerRimsParams,
|
||||
visuals: PD.MultiSelect(['bilayer-planes', 'bilayer-rims'], PD.objectToOptions(MembraneOrientationVisuals)),
|
||||
};
|
||||
export type MembraneOrientationParams = typeof MembraneOrientationParams
|
||||
export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
|
||||
|
||||
export function getMembraneOrientationParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
return PD.clone(MembraneOrientationParams);
|
||||
}
|
||||
|
||||
export type MembraneOrientationRepresentation = StructureRepresentation<MembraneOrientationParams>
|
||||
export function MembraneOrientationRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MembraneOrientationParams>): MembraneOrientationRepresentation {
|
||||
return Representation.createMulti('Membrane Orientation', ctx, getParams, StructureRepresentationStateBuilder, MembraneOrientationVisuals as unknown as Representation.Def<Structure, MembraneOrientationParams>);
|
||||
}
|
||||
|
||||
export const MembraneOrientationRepresentationProvider = StructureRepresentationProvider({
|
||||
name: 'membrane-orientation',
|
||||
label: 'Membrane Orientation',
|
||||
description: 'Displays a grid of points representing membrane layers.',
|
||||
factory: MembraneOrientationRepresentation,
|
||||
getParams: getMembraneOrientationParams,
|
||||
defaultValues: PD.getDefaultValues(MembraneOrientationParams),
|
||||
defaultColorTheme: { name: 'shape-group' },
|
||||
defaultSizeTheme: { name: 'shape-group' },
|
||||
isApplicable: (structure: Structure) => structure.elementCount > 0,
|
||||
ensureCustomProperties: {
|
||||
attach: (ctx: CustomProperty.Context, structure: Structure) => MembraneOrientationProvider.attach(ctx, structure, void 0, true),
|
||||
detach: (data) => MembraneOrientationProvider.ref(data, false)
|
||||
}
|
||||
});
|
||||
|
||||
function membraneLabel(data: Structure) {
|
||||
return `${lociLabel(Structure.Loci(data))} | Membrane Orientation`;
|
||||
}
|
||||
|
||||
function getBilayerRims(ctx: RuntimeContext, data: Structure, props: BilayerRimsProps, shape?: Shape<Lines>): Shape<Lines> {
|
||||
const { planePoint1: p1, planePoint2: p2, centroid, radius } = MembraneOrientationProvider.get(data).value!;
|
||||
const scaledRadius = props.radiusFactor * radius;
|
||||
const builder = LinesBuilder.create(128, 64, shape?.geometry);
|
||||
getLayerCircle(builder, p1, centroid, scaledRadius, props);
|
||||
getLayerCircle(builder, p2, centroid, scaledRadius, props);
|
||||
return Shape.create('Bilayer rims', data, builder.getLines(), () => props.color, () => props.linesSize, () => membraneLabel(data));
|
||||
}
|
||||
|
||||
function getLayerCircle(builder: LinesBuilder, p: Vec3, centroid: Vec3, radius: number, props: BilayerRimsProps, shape?: Shape<Lines>) {
|
||||
const circle = getCircle(p, centroid, radius);
|
||||
const { indices, vertices } = circle;
|
||||
for (let j = 0, jl = indices.length; j < jl; j += 3) {
|
||||
if (props.dashedLines && j % 2 === 1) continue; // draw every other segment to get dashes
|
||||
const start = indices[j] * 3;
|
||||
const end = indices[j + 1] * 3;
|
||||
const startX = vertices[start];
|
||||
const startY = vertices[start + 1];
|
||||
const startZ = vertices[start + 2];
|
||||
const endX = vertices[end];
|
||||
const endY = vertices[end + 1];
|
||||
const endZ = vertices[end + 2];
|
||||
builder.add(startX, startY, startZ, endX, endY, endZ, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const tmpMat = Mat4();
|
||||
const tmpV = Vec3();
|
||||
function getCircle(p: Vec3, centroid: Vec3, radius: number) {
|
||||
if (Vec3.dot(Vec3.unitY, Vec3.sub(tmpV, p, centroid)) === 0) {
|
||||
Mat4.targetTo(tmpMat, p, centroid, Vec3.unitY);
|
||||
} else {
|
||||
Mat4.targetTo(tmpMat, p, centroid, Vec3.unitX);
|
||||
}
|
||||
Mat4.setTranslation(tmpMat, p);
|
||||
Mat4.mul(tmpMat, tmpMat, Mat4.rotX90);
|
||||
|
||||
const circle = Circle({ radius, segments: 64 });
|
||||
return transformPrimitive(circle, tmpMat);
|
||||
}
|
||||
|
||||
function getBilayerPlanes(ctx: RuntimeContext, data: Structure, props: BilayerPlanesProps, shape?: Shape<Mesh>): Shape<Mesh> {
|
||||
const { planePoint1: p1, planePoint2: p2, centroid, radius } = MembraneOrientationProvider.get(data).value!;
|
||||
const state = MeshBuilder.createState(128, 64, shape && shape.geometry);
|
||||
const scaledRadius = props.radiusFactor * radius;
|
||||
getLayerPlane(state, p1, centroid, scaledRadius);
|
||||
getLayerPlane(state, p2, centroid, scaledRadius);
|
||||
return Shape.create('Bilayer planes', data, MeshBuilder.getMesh(state), () => props.color, () => 1, () => membraneLabel(data));
|
||||
}
|
||||
|
||||
function getLayerPlane(state: MeshBuilder.State, p: Vec3, centroid: Vec3, radius: number) {
|
||||
const circle = getCircle(p, centroid, radius);
|
||||
state.currentGroup = 0;
|
||||
MeshBuilder.addPrimitive(state, Mat4.id, circle);
|
||||
MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle);
|
||||
}
|
||||
95
src/extensions/cellpack/color/generate.ts
Normal file
95
src/extensions/cellpack/color/generate.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { ThemeDataContext } from '../../../mol-theme/theme';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { Color } from '../../../mol-util/color';
|
||||
import { getPalette } from '../../../mol-util/color/palette';
|
||||
import { ColorTheme, LocationColor } from '../../../mol-theme/color';
|
||||
import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
|
||||
import { StructureElement, Bond, Model } from '../../../mol-model/structure';
|
||||
import { Location } from '../../../mol-model/location';
|
||||
import { CellPackInfoProvider } from '../property';
|
||||
import { distinctColors } from '../../../mol-util/color/distinct';
|
||||
import { Hcl } from '../../../mol-util/color/spaces/hcl';
|
||||
|
||||
const DefaultColor = Color(0xCCCCCC);
|
||||
const Description = 'Gives every model in a CellPack packing a unique generated color similar to other models in the packing.';
|
||||
|
||||
export const CellPackGenerateColorThemeParams = {};
|
||||
export type CellPackGenerateColorThemeParams = typeof CellPackGenerateColorThemeParams
|
||||
export function getCellPackGenerateColorThemeParams(ctx: ThemeDataContext) {
|
||||
return CellPackGenerateColorThemeParams; // TODO return copy
|
||||
}
|
||||
|
||||
export function CellPackGenerateColorTheme(ctx: ThemeDataContext, props: PD.Values<CellPackGenerateColorThemeParams>): ColorTheme<CellPackGenerateColorThemeParams> {
|
||||
let color: LocationColor;
|
||||
let legend: ScaleLegend | TableLegend | undefined;
|
||||
|
||||
const info = ctx.structure && CellPackInfoProvider.get(ctx.structure).value;
|
||||
|
||||
if (ctx.structure && info) {
|
||||
const colors = distinctColors(info.packingsCount);
|
||||
const hcl = Hcl.fromColor(Hcl(), colors[info.packingIndex]);
|
||||
|
||||
const hue = [Math.max(0, hcl[0] - 35), Math.min(360, hcl[0] + 35)] as [number, number];
|
||||
|
||||
const { models } = ctx.structure.root;
|
||||
|
||||
let size = 0;
|
||||
for (const m of models) size = Math.max(size, Model.TrajectoryInfo.get(m).size);
|
||||
|
||||
const palette = getPalette(size, { palette: {
|
||||
name: 'generate',
|
||||
params: {
|
||||
hue, chroma: [30, 80], luminance: [15, 85],
|
||||
clusteringStepCount: 50, minSampleCount: 800, maxCount: 75
|
||||
}
|
||||
} }, { minLabel: 'Min', maxLabel: 'Max' });
|
||||
legend = palette.legend;
|
||||
const modelColor = new Map<number, Color>();
|
||||
for (let i = 0, il = models.length; i < il; ++i) {
|
||||
const idx = Model.TrajectoryInfo.get(models[i]).index;
|
||||
modelColor.set(Model.TrajectoryInfo.get(models[i]).index, palette.color(idx));
|
||||
}
|
||||
|
||||
color = (location: Location): Color => {
|
||||
if (StructureElement.Location.is(location)) {
|
||||
return modelColor.get(Model.TrajectoryInfo.get(location.unit.model).index)!;
|
||||
} else if (Bond.isLocation(location)) {
|
||||
return modelColor.get(Model.TrajectoryInfo.get(location.aUnit.model).index)!;
|
||||
}
|
||||
return DefaultColor;
|
||||
};
|
||||
} else {
|
||||
color = () => DefaultColor;
|
||||
}
|
||||
|
||||
return {
|
||||
factory: CellPackGenerateColorTheme,
|
||||
granularity: 'instance',
|
||||
color,
|
||||
props,
|
||||
description: Description,
|
||||
legend
|
||||
};
|
||||
}
|
||||
|
||||
export const CellPackGenerateColorThemeProvider: ColorTheme.Provider<CellPackGenerateColorThemeParams, 'cellpack-generate'> = {
|
||||
name: 'cellpack-generate',
|
||||
label: 'CellPack Generate',
|
||||
category: ColorTheme.Category.Chain,
|
||||
factory: CellPackGenerateColorTheme,
|
||||
getParams: getCellPackGenerateColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(CellPackGenerateColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => {
|
||||
return (
|
||||
!!ctx.structure && ctx.structure.elementCount > 0 &&
|
||||
!!CellPackInfoProvider.get(ctx.structure).value
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
75
src/extensions/cellpack/color/provided.ts
Normal file
75
src/extensions/cellpack/color/provided.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { ThemeDataContext } from '../../../mol-theme/theme';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { Color } from '../../../mol-util/color';
|
||||
import { ColorTheme, LocationColor } from '../../../mol-theme/color';
|
||||
import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
|
||||
import { StructureElement, Model, Bond } from '../../../mol-model/structure';
|
||||
import { Location } from '../../../mol-model/location';
|
||||
import { CellPackInfoProvider } from '../property';
|
||||
|
||||
const DefaultColor = Color(0xCCCCCC);
|
||||
const Description = 'Gives every model in a CellPack the color provied in the packing data.';
|
||||
|
||||
export const CellPackProvidedColorThemeParams = {};
|
||||
export type CellPackProvidedColorThemeParams = typeof CellPackProvidedColorThemeParams
|
||||
export function getCellPackProvidedColorThemeParams(ctx: ThemeDataContext) {
|
||||
return CellPackProvidedColorThemeParams; // TODO return copy
|
||||
}
|
||||
|
||||
export function CellPackProvidedColorTheme(ctx: ThemeDataContext, props: PD.Values<CellPackProvidedColorThemeParams>): ColorTheme<CellPackProvidedColorThemeParams> {
|
||||
let color: LocationColor;
|
||||
let legend: ScaleLegend | TableLegend | undefined;
|
||||
|
||||
const info = ctx.structure && CellPackInfoProvider.get(ctx.structure).value;
|
||||
|
||||
if (ctx.structure && info?.colors) {
|
||||
const { models } = ctx.structure.root;
|
||||
const modelColor = new Map<number, Color>();
|
||||
for (let i = 0, il = models.length; i < il; ++i) {
|
||||
const idx = Model.TrajectoryInfo.get(models[i]).index;
|
||||
modelColor.set(Model.TrajectoryInfo.get(models[i]).index, info.colors[idx]);
|
||||
}
|
||||
|
||||
color = (location: Location): Color => {
|
||||
if (StructureElement.Location.is(location)) {
|
||||
return modelColor.get(Model.TrajectoryInfo.get(location.unit.model).index)!;
|
||||
} else if (Bond.isLocation(location)) {
|
||||
return modelColor.get(Model.TrajectoryInfo.get(location.aUnit.model).index)!;
|
||||
}
|
||||
return DefaultColor;
|
||||
};
|
||||
} else {
|
||||
color = () => DefaultColor;
|
||||
}
|
||||
|
||||
return {
|
||||
factory: CellPackProvidedColorTheme,
|
||||
granularity: 'instance',
|
||||
color,
|
||||
props,
|
||||
description: Description,
|
||||
legend
|
||||
};
|
||||
}
|
||||
|
||||
export const CellPackProvidedColorThemeProvider: ColorTheme.Provider<CellPackProvidedColorThemeParams, 'cellpack-provided'> = {
|
||||
name: 'cellpack-provided',
|
||||
label: 'CellPack Provided',
|
||||
category: ColorTheme.Category.Chain,
|
||||
factory: CellPackProvidedColorTheme,
|
||||
getParams: getCellPackProvidedColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(CellPackProvidedColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => {
|
||||
return (
|
||||
!!ctx.structure && ctx.structure.elementCount > 0 &&
|
||||
Model.TrajectoryInfo.get(ctx.structure.models[0]).size > 1 &&
|
||||
!!CellPackInfoProvider.get(ctx.structure).value?.colors
|
||||
);
|
||||
}
|
||||
};
|
||||
229
src/extensions/cellpack/curve.ts
Normal file
229
src/extensions/cellpack/curve.ts
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Vec3, Quat, Mat4 } from '../../mol-math/linear-algebra';
|
||||
import { NumberArray } from '../../mol-util/type-helpers';
|
||||
|
||||
interface Frame {
|
||||
t: Vec3,
|
||||
r: Vec3,
|
||||
s: Vec3,
|
||||
}
|
||||
|
||||
const a0Tmp = Vec3();
|
||||
const a1Tmp = Vec3();
|
||||
const a2Tmp = Vec3();
|
||||
const a3Tmp = Vec3();
|
||||
function CubicInterpolate(out: Vec3, y0: Vec3, y1: Vec3, y2: Vec3, y3: Vec3, mu: number): Vec3 {
|
||||
const mu2 = mu * mu;
|
||||
Vec3.sub(a0Tmp, y3, y2);
|
||||
Vec3.sub(a0Tmp, a0Tmp, y0);
|
||||
Vec3.add(a0Tmp, a0Tmp, y1);
|
||||
|
||||
Vec3.sub(a1Tmp, y0, y1);
|
||||
Vec3.sub(a1Tmp, a1Tmp, a0Tmp);
|
||||
|
||||
Vec3.sub(a2Tmp, y2, y0);
|
||||
|
||||
Vec3.copy(a3Tmp, y1);
|
||||
|
||||
out[0] = a0Tmp[0] * mu * mu2 + a1Tmp[0] * mu2 + a2Tmp[0] * mu + a3Tmp[0];
|
||||
out[1] = a0Tmp[1] * mu * mu2 + a1Tmp[1] * mu2 + a2Tmp[1] * mu + a3Tmp[1];
|
||||
out[2] = a0Tmp[2] * mu * mu2 + a1Tmp[2] * mu2 + a2Tmp[2] * mu + a3Tmp[2];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
const cp0 = Vec3();
|
||||
const cp1 = Vec3();
|
||||
const cp2 = Vec3();
|
||||
const cp3 = Vec3();
|
||||
const currentPosition = Vec3();
|
||||
function ResampleControlPoints(points: NumberArray, segmentLength: number) {
|
||||
const nP = points.length / 3;
|
||||
// insert a point at the end and at the begining
|
||||
// controlPoints.Insert(0, controlPoints[0] + (controlPoints[0] - controlPoints[1]) / 2.0f);
|
||||
// controlPoints.Add(controlPoints[nP - 1] + (controlPoints[nP - 1] - controlPoints[nP - 2]) / 2.0f);
|
||||
|
||||
const resampledControlPoints: Vec3[] = [];
|
||||
// resampledControlPoints.Add(controlPoints[0]);
|
||||
// resampledControlPoints.Add(controlPoints[1]);
|
||||
|
||||
let idx = 1;
|
||||
// const currentPosition = Vec3.create(points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2])
|
||||
Vec3.fromArray(currentPosition, points, idx * 3);
|
||||
|
||||
let lerpValue = 0.0;
|
||||
|
||||
// Normalize the distance between control points
|
||||
while (true) {
|
||||
if (idx + 2 >= nP) break;
|
||||
Vec3.fromArray(cp0, points, (idx - 1) * 3);
|
||||
Vec3.fromArray(cp1, points, idx * 3);
|
||||
Vec3.fromArray(cp2, points, (idx + 1) * 3);
|
||||
Vec3.fromArray(cp3, points, (idx + 2) * 3);
|
||||
// const cp0 = Vec3.create(points[(idx-1)*3], points[(idx-1)*3+1], points[(idx-1)*3+2]) // controlPoints[currentPointId - 1];
|
||||
// const cp1 = Vec3.create(points[idx*3], points[idx*3+1], points[idx*3+2]) // controlPoints[currentPointId];
|
||||
// const cp2 = Vec3.create(points[(idx+1)*3], points[(idx+1)*3+1], points[(idx+1)*3+2]) // controlPoints[currentPointId + 1];
|
||||
// const cp3 = Vec3.create(points[(idx+2)*3], points[(idx+2)*3+1], points[(idx+2)*3+2]); // controlPoints[currentPointId + 2];
|
||||
let found = false;
|
||||
for (; lerpValue <= 1; lerpValue += 0.01) {
|
||||
// lerp?slerp
|
||||
// let candidate:Vec3 = Vec3.lerp(Vec3.zero(), cp0, cp1, lerpValue);
|
||||
// const candidate:Vec3 = Vec3.bezier(Vec3.zero(), cp0, cp1, cp2, cp3, lerpValue);
|
||||
const candidate = CubicInterpolate(Vec3(), cp0, cp1, cp2, cp3, lerpValue);
|
||||
const d = Vec3.distance(currentPosition, candidate);
|
||||
if (d > segmentLength) {
|
||||
resampledControlPoints.push(candidate);
|
||||
Vec3.copy(currentPosition, candidate);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
lerpValue = 0;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
return resampledControlPoints;
|
||||
}
|
||||
|
||||
|
||||
const prevV = Vec3();
|
||||
const tmpV1 = Vec3();
|
||||
const tmpV2 = Vec3();
|
||||
const tmpV3 = Vec3();
|
||||
|
||||
// easier to align to theses normals
|
||||
function GetSmoothNormals(points: Vec3[]) {
|
||||
const nP: number = points.length;
|
||||
const smoothNormals: Vec3[] = [];
|
||||
if (points.length < 3) {
|
||||
for (let i = 0; i < points.length; ++i)
|
||||
smoothNormals.push(Vec3.normalize(Vec3(), points[i]));
|
||||
return smoothNormals;
|
||||
}
|
||||
let p0 = points[0];
|
||||
let p1 = points[1];
|
||||
let p2 = points[2];
|
||||
const p21 = Vec3.sub(tmpV1, p2, p1);
|
||||
const p01 = Vec3.sub(tmpV2, p0, p1);
|
||||
const p0121 = Vec3.cross(tmpV3, p01, p21);
|
||||
Vec3.normalize(prevV, p0121);
|
||||
smoothNormals.push(Vec3.clone(prevV));
|
||||
for (let i = 1; i < points.length - 1; ++i) {
|
||||
p0 = points[i - 1];
|
||||
p1 = points[i];
|
||||
p2 = points[i + 1];
|
||||
const t = Vec3.normalize(tmpV1, Vec3.sub(tmpV1, p2, p0));
|
||||
const b = Vec3.normalize(tmpV2, Vec3.cross(tmpV2, t, prevV));
|
||||
const n = Vec3.normalize(Vec3(), Vec3.cross(tmpV3, t, b));
|
||||
Vec3.negate(n, n);
|
||||
Vec3.copy(prevV, n);
|
||||
smoothNormals.push(n);
|
||||
}
|
||||
const last = Vec3();
|
||||
Vec3.normalize(last, Vec3.cross(last,
|
||||
Vec3.sub(tmpV1, points[nP - 3], points[nP - 2]),
|
||||
Vec3.sub(tmpV2, points[nP - 2], points[nP - 1]))
|
||||
);
|
||||
smoothNormals.push(last);
|
||||
return smoothNormals;
|
||||
}
|
||||
|
||||
const frameTmpV1 = Vec3();
|
||||
const frameTmpV2 = Vec3();
|
||||
const frameTmpV3 = Vec3();
|
||||
|
||||
function getFrame(reference: Vec3, tangent: Vec3) {
|
||||
const t = Vec3.normalize(Vec3(), tangent);
|
||||
// make reference vector orthogonal to tangent
|
||||
const proj_r_to_t = Vec3.scale(
|
||||
frameTmpV1, tangent, Vec3.dot(reference, tangent) / Vec3.dot(tangent, tangent)
|
||||
);
|
||||
const r = Vec3.normalize(Vec3(), Vec3.sub(frameTmpV2, reference, proj_r_to_t));
|
||||
// make bitangent vector orthogonal to the others
|
||||
const s = Vec3.normalize(Vec3(), Vec3.cross(frameTmpV3, t, r));
|
||||
return { t, r, s };
|
||||
}
|
||||
|
||||
const mfTmpV1 = Vec3();
|
||||
const mfTmpV2 = Vec3();
|
||||
const mfTmpV3 = Vec3();
|
||||
const mfTmpV4 = Vec3();
|
||||
const mfTmpV5 = Vec3();
|
||||
const mfTmpV6 = Vec3();
|
||||
const mfTmpV7 = Vec3();
|
||||
const mfTmpV8 = Vec3();
|
||||
const mfTmpV9 = Vec3();
|
||||
|
||||
// easier to align to theses normals
|
||||
// https://github.com/bzamecnik/gpg/blob/master/rotation-minimizing-frame/rmf.py
|
||||
function GetMiniFrame(points: Vec3[], normals: Vec3[]) {
|
||||
const frames: Frame[] = [];
|
||||
const t0 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[1], points[0]));
|
||||
frames.push(getFrame(normals[0], t0));
|
||||
|
||||
for (let i = 0; i < points.length - 2; ++i) {
|
||||
const t2 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[i + 2], points[i + 1]));
|
||||
const v1 = Vec3.sub(mfTmpV2, points[i + 1], points[i]); // this is tangeant
|
||||
const c1 = Vec3.dot(v1, v1);
|
||||
// compute r_i^L = R_1 * r_i
|
||||
const v1r = Vec3.scale(mfTmpV3, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].r));
|
||||
const ref_L_i = Vec3.sub(mfTmpV4, frames[i].r, v1r);
|
||||
// compute t_i^L = R_1 * t_i
|
||||
const v1t = Vec3.scale(mfTmpV5, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].t));
|
||||
const tan_L_i = Vec3.sub(mfTmpV6, frames[i].t, v1t);
|
||||
// # compute reflection vector of R_2
|
||||
const v2 = Vec3.sub(mfTmpV7, t2, tan_L_i);
|
||||
const c2 = Vec3.dot(v2, v2);
|
||||
// compute r_(i+1) = R_2 * r_i^L
|
||||
const v2l = Vec3.scale(mfTmpV8, v1, (2.0 / c2) * Vec3.dot(v2, ref_L_i));
|
||||
const ref_next = Vec3.sub(mfTmpV9, ref_L_i, v2l); // ref_L_i - (2 / c2) * v2.dot(ref_L_i) * v2
|
||||
frames.push(getFrame(ref_next, t2)); // frames.append(Frame(ref_next, tangents[i+1]))
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
const rpTmpVec1 = Vec3();
|
||||
|
||||
export function getMatFromResamplePoints(points: NumberArray, segmentLength: number, resample: boolean) {
|
||||
let new_points: Vec3[] = [];
|
||||
if (resample) new_points = ResampleControlPoints(points, segmentLength);
|
||||
else {
|
||||
for (let idx = 0; idx < points.length / 3; ++idx) {
|
||||
new_points.push(Vec3.fromArray(Vec3.zero(), points, idx * 3));
|
||||
}
|
||||
}
|
||||
const npoints = new_points.length;
|
||||
const new_normal = GetSmoothNormals(new_points);
|
||||
const frames = GetMiniFrame(new_points, new_normal);
|
||||
const limit = npoints;
|
||||
const transforms: Mat4[] = [];
|
||||
const pti = Vec3.copy(rpTmpVec1, new_points[0]);
|
||||
for (let i = 0; i < npoints - 2; ++i) {
|
||||
const pti1: Vec3 = new_points[i + 1]; // Vec3.create(points[(i+1)*3],points[(i+1)*3+1],points[(i+1)*3+2]);
|
||||
const d = Vec3.distance(pti, pti1);
|
||||
if (d >= segmentLength) {
|
||||
// use twist or random?
|
||||
const quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t); // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal
|
||||
const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random() * 3.60); // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();//
|
||||
const m = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)); // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat));
|
||||
// let pos:Vec3 = Vec3.add(Vec3.zero(),pti1,pti)
|
||||
// pos = Vec3.scale(pos,pos,1.0/2.0);
|
||||
// Vec3.makeRotation(Mat4.zero(),Vec3.create(0,0,1),frames[i].t);//
|
||||
Mat4.setTranslation(m, pti1);
|
||||
// let m2:Mat4 = GetTubePropertiesMatrix(pti,pti1);
|
||||
// let q:Quat = Quat.rotationTo(Quat.zero(), Vec3.create(0,1,0),Vec3.create(0,0,1))
|
||||
// m2=Mat4.mul(Mat4.identity(),Mat4.fromQuat(Mat4.zero(),q),m2);
|
||||
transforms.push(m);
|
||||
Vec3.copy(pti, pti1);
|
||||
}
|
||||
if (transforms.length >= limit) break;
|
||||
}
|
||||
return transforms;
|
||||
}
|
||||
118
src/extensions/cellpack/data.ts
Normal file
118
src/extensions/cellpack/data.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Vec3, Quat } from '../../mol-math/linear-algebra';
|
||||
|
||||
export interface CellPack {
|
||||
cell: Cell
|
||||
packings: CellPacking[]
|
||||
}
|
||||
|
||||
export interface CellPacking {
|
||||
name: string,
|
||||
location: 'surface' | 'interior' | 'cytoplasme'
|
||||
ingredients: Packing['ingredients']
|
||||
compartment?: CellCompartment
|
||||
}
|
||||
|
||||
export interface CellCompartment {
|
||||
filename?: string
|
||||
geom_type?: 'raw' | 'file' | 'sphere' | 'mb' | 'None'
|
||||
compartment_primitives?: CompartmentPrimitives
|
||||
}
|
||||
|
||||
export interface Cell {
|
||||
recipe: Recipe
|
||||
options?: RecipeOptions
|
||||
cytoplasme?: Packing
|
||||
compartments?: { [key: string]: Compartment }
|
||||
mapping_ids?: { [key: number]: [number, string] }
|
||||
}
|
||||
|
||||
export interface RecipeOptions {
|
||||
resultfile?: string
|
||||
}
|
||||
|
||||
export interface Recipe {
|
||||
setupfile: string
|
||||
paths: [string, string][] // [name: string, path: string][]
|
||||
version: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface Compartment {
|
||||
surface?: Packing
|
||||
interior?: Packing
|
||||
geom?: unknown
|
||||
geom_type?: 'raw' | 'file' | 'sphere' | 'mb' | 'None'
|
||||
mb?: CompartmentPrimitives
|
||||
}
|
||||
|
||||
// Primitives discribing a compartment
|
||||
export const enum CompartmentPrimitiveType {
|
||||
MetaBall = 0,
|
||||
Sphere = 1,
|
||||
Cube = 2,
|
||||
Cylinder = 3,
|
||||
Cone = 4,
|
||||
Plane = 5,
|
||||
None = 6
|
||||
}
|
||||
|
||||
export interface CompartmentPrimitives{
|
||||
positions?: number[];
|
||||
radii?: number[];
|
||||
types?: CompartmentPrimitiveType[];
|
||||
}
|
||||
|
||||
|
||||
export interface Packing {
|
||||
ingredients: { [key: string]: Ingredient }
|
||||
}
|
||||
|
||||
export interface Positions {
|
||||
coords?: Vec3[];
|
||||
}
|
||||
|
||||
export interface Radii {
|
||||
radii?: number[];
|
||||
}
|
||||
|
||||
export interface Ingredient {
|
||||
source: IngredientSource;
|
||||
results: [Vec3, Quat][];
|
||||
name: string;
|
||||
/** Vec3[]];CoarseGraind Beads coordinates LOD */
|
||||
positions?: [Positions];
|
||||
/** number[]];CoarseGraind Beads radii LOD */
|
||||
radii?: [Radii];
|
||||
/** Number of `curveX` properties in the object where `X` is a 0-indexed number */
|
||||
nbCurve?: number;
|
||||
uLength?: number;
|
||||
/** Curve properties are Vec3[] but that is not expressable in TypeScript */
|
||||
[curveX: string]: unknown;
|
||||
/** the orientation in the membrane */
|
||||
principalAxis?: Vec3;
|
||||
principalVector?: Vec3;
|
||||
/** offset along membrane */
|
||||
offset?: Vec3;
|
||||
ingtype?: string;
|
||||
color?: Vec3;
|
||||
confidence?: number;
|
||||
Type?: string;
|
||||
}
|
||||
|
||||
export interface IngredientSource {
|
||||
pdb: string;
|
||||
bu?: string; /** biological unit e.g AU,BU1,etc.. */
|
||||
selection?: string; /** NGL selection or :A or :B etc.. */
|
||||
model?: string; /** model number e.g 0,1,2... */
|
||||
transform: {
|
||||
center: boolean;
|
||||
translate?: Vec3;
|
||||
};
|
||||
biomt?: boolean;
|
||||
}
|
||||
32
src/extensions/cellpack/index.ts
Normal file
32
src/extensions/cellpack/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { PluginBehavior } from '../../mol-plugin/behavior';
|
||||
import { LoadCellPackModel } from './model';
|
||||
import { CellPackGenerateColorThemeProvider } from './color/generate';
|
||||
import { CellPackProvidedColorThemeProvider } from './color/provided';
|
||||
|
||||
export const CellPack = PluginBehavior.create<{ autoAttach: boolean, showTooltip: boolean }>({
|
||||
name: 'cellpack',
|
||||
category: 'custom-props',
|
||||
display: {
|
||||
name: 'CellPack',
|
||||
description: 'CellPack Model Loading and Viewing.'
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
|
||||
register(): void {
|
||||
this.ctx.state.data.actions.add(LoadCellPackModel);
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.add(CellPackGenerateColorThemeProvider);
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.add(CellPackProvidedColorThemeProvider);
|
||||
}
|
||||
|
||||
unregister() {
|
||||
this.ctx.state.data.actions.remove(LoadCellPackModel);
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.remove(CellPackGenerateColorThemeProvider);
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.remove(CellPackProvidedColorThemeProvider);
|
||||
}
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user