mirror of
https://github.com/molstar/molstar.git
synced 2026-06-06 14:44:22 +08:00
Compare commits
184 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -62,6 +62,8 @@ This project builds on experience from previous solutions:
|
||||
### 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
|
||||
|
||||
|
||||
60
data/cif-core.csv
Normal file
60
data/cif-core.csv
Normal file
@@ -0,0 +1,60 @@
|
||||
audit.block_doi
|
||||
|
||||
database_code.depnum_ccdc_archive
|
||||
|
||||
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_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_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_2
|
||||
geom_bond.publ_flag
|
||||
|
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
|
||||
|
||||
|
||||
|
||||
564
package-lock.json
generated
564
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
33
package.json
33
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "0.3.2",
|
||||
"version": "0.4.2",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -78,40 +78,39 @@
|
||||
"jest": "^24.9.0",
|
||||
"jest-raw-loader": "^1.0.1",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"raw-loader": "^3.1.0",
|
||||
"resolve-url-loader": "^3.1.0",
|
||||
"resolve-url-loader": "^3.1.1",
|
||||
"sass-loader": "^8.0.0",
|
||||
"simple-git": "^1.126.0",
|
||||
"style-loader": "^1.0.0",
|
||||
"ts-jest": "^24.1.0",
|
||||
"tslint": "^5.20.0",
|
||||
"typescript": "^3.6.4",
|
||||
"webpack": "^4.41.0",
|
||||
"webpack-cli": "^3.3.9"
|
||||
"tslint": "^5.20.1",
|
||||
"typescript": "^3.7.2",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.3.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^1.0.36",
|
||||
"@types/benchmark": "^1.0.31",
|
||||
"@types/compression": "1.0.1",
|
||||
"@types/express": "^4.17.1",
|
||||
"@types/jest": "^24.0.18",
|
||||
"@types/node": "^12.7.12",
|
||||
"@types/node-fetch": "^2.5.2",
|
||||
"@types/react": "^16.9.5",
|
||||
"@types/react-dom": "^16.9.1",
|
||||
"@types/express": "^4.17.2",
|
||||
"@types/jest": "^24.0.23",
|
||||
"@types/node": "^12.12.9",
|
||||
"@types/node-fetch": "^2.5.3",
|
||||
"@types/react": "^16.9.11",
|
||||
"@types/react-dom": "^16.9.4",
|
||||
"@types/swagger-ui-dist": "3.0.3",
|
||||
"@types/webgl2": "0.0.5",
|
||||
"argparse": "^1.0.10",
|
||||
"compression": "^1.7.4",
|
||||
"express": "^4.17.1",
|
||||
"graphql": "^14.5.8",
|
||||
"immutable": "^3.8.2",
|
||||
"node-fetch": "^2.6.0",
|
||||
"react": "^16.10.2",
|
||||
"react-dom": "^16.10.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"rxjs": "^6.5.3",
|
||||
"swagger-ui-dist": "^3.23.11",
|
||||
"swagger-ui-dist": "^3.24.3",
|
||||
"util.promisify": "^1.0.0",
|
||||
"xhr2": "^0.2.0"
|
||||
}
|
||||
|
||||
@@ -105,6 +105,10 @@
|
||||
|
||||
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
|
||||
|
||||
addHeader('Interactivity');
|
||||
addControl('Highlight seq_id=7', () => BasicMolStarWrapper.interactivity.highlightOn());
|
||||
addControl('Clear Highlight', () => BasicMolStarWrapper.interactivity.clearHighlight());
|
||||
|
||||
addHeader('Tests');
|
||||
|
||||
addControl('Static Superposition', () => BasicMolStarWrapper.tests.staticSuperposition());
|
||||
|
||||
@@ -11,14 +11,16 @@ 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 { PluginStateObject as PSO, PluginStateObject } 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';
|
||||
import { PDBeStructureQualityReport } from '../../mol-plugin/behavior/dynamic/custom-props';
|
||||
import { CustomToastMessage } from './controls';
|
||||
import { EmptyLoci } from '../../mol-model/loci';
|
||||
import { StructureSelection } from '../../mol-model/structure';
|
||||
import { Script } from '../../mol-script/script';
|
||||
require('mol-plugin/skin/light.scss')
|
||||
|
||||
type SupportedFormats = 'cif' | 'pdb'
|
||||
@@ -63,7 +65,7 @@ class BasicWrapper {
|
||||
}
|
||||
|
||||
private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: 'seq' })
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'), { ref: 'seq-visual' });
|
||||
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
|
||||
@@ -144,6 +146,22 @@ class BasicWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
interactivity = {
|
||||
highlightOn: () => {
|
||||
const seq_id = 7;
|
||||
const data = (this.plugin.state.dataState.select('asm')[0].obj as PluginStateObject.Molecule.Structure).data;
|
||||
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.interactivity.lociHighlights.highlightOnly({ loci });
|
||||
},
|
||||
clearHighlight: () => {
|
||||
this.plugin.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
|
||||
}
|
||||
}
|
||||
|
||||
tests = {
|
||||
staticSuperposition: async () => {
|
||||
const state = this.plugin.state.dataState;
|
||||
|
||||
@@ -86,7 +86,7 @@ export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[]
|
||||
|
||||
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 selections = xs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.obj!.data))));
|
||||
|
||||
const transforms = superposeStructures(selections);
|
||||
const visuals = state.build();
|
||||
|
||||
@@ -10,7 +10,7 @@ import { PluginStateObject as PSO } from '../../../../mol-plugin/state/objects';
|
||||
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
|
||||
import { Ingredient, CellPacking, Cell } from './data';
|
||||
import { getFromPdb, getFromCellPackDB } from './util';
|
||||
import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext } from '../../../../mol-model/structure';
|
||||
import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext, Unit } from '../../../../mol-model/structure';
|
||||
import { trajectoryFromMmCIF } from '../../../../mol-model-formats/structure/mmcif';
|
||||
import { trajectoryFromPDB } from '../../../../mol-model-formats/structure/pdb';
|
||||
import { Mat4, Vec3, Quat } from '../../../../mol-math/linear-algebra';
|
||||
@@ -268,7 +268,7 @@ export function createStructureFromCellPack(packing: CellPacking, baseUrl: strin
|
||||
for (const u of s.units) {
|
||||
const invariantId = u.invariantId + offsetInvariantId
|
||||
if (u.invariantId > maxInvariantId) maxInvariantId = u.invariantId
|
||||
builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, invariantId)
|
||||
builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, Unit.Trait.None, invariantId)
|
||||
}
|
||||
offsetInvariantId += maxInvariantId
|
||||
}
|
||||
@@ -385,17 +385,17 @@ export const LoadCellPackModel = StateAction.build({
|
||||
const hue = [Math.max(0, hcl[0] - 35), Math.min(360, hcl[0] + 35)] as [number, number]
|
||||
const p = { packing: i, baseUrl: params.baseUrl }
|
||||
|
||||
const expression = params.preset.traceOnly
|
||||
? MS.struct.generator.atomGroups({
|
||||
let cellpackTree = tree.apply(StructureFromCellpack, p)
|
||||
if (params.preset.traceOnly) {
|
||||
const expression = MS.struct.generator.atomGroups({
|
||||
'atom-test': MS.core.logic.or([
|
||||
MS.core.rel.eq([MS.ammp('label_atom_id'), 'CA']),
|
||||
MS.core.rel.eq([MS.ammp('label_atom_id'), 'P'])
|
||||
])
|
||||
})
|
||||
: MS.struct.generator.all()
|
||||
|
||||
tree.apply(StructureFromCellpack, p)
|
||||
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression }, { state: { isGhost: true } })
|
||||
cellpackTree = cellpackTree.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression }, { state: { isGhost: true } })
|
||||
}
|
||||
cellpackTree
|
||||
.apply(StateTransforms.Representation.StructureRepresentation3D,
|
||||
StructureRepresentation3DHelpers.createParams(ctx, Structure.Empty, {
|
||||
repr: getReprParams(ctx, params.preset),
|
||||
|
||||
@@ -28,7 +28,6 @@ import { BuiltInColorThemes } from '../../mol-theme/color';
|
||||
import { BuiltInSizeThemes } from '../../mol-theme/size';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { InitVolumeStreaming, CreateVolumeStreamingInfo } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
|
||||
import { ParamDefinition } from '../../mol-util/param-definition';
|
||||
import { DefaultCanvas3DParams, Canvas3DProps } from '../../mol-canvas3d/canvas3d';
|
||||
// import { Vec3 } from 'mol-math/linear-algebra';
|
||||
// import { ParamDefinition } from 'mol-util/param-definition';
|
||||
@@ -315,9 +314,11 @@ class MolStarProteopediaWrapper {
|
||||
experimentalData = {
|
||||
init: async (parent: Element) => {
|
||||
const asm = this.state.select(StateElements.Assembly)[0].obj!;
|
||||
const params = ParamDefinition.getDefaultValues(InitVolumeStreaming.definition.params!(asm, this.plugin));
|
||||
params.behaviorRef = StateElements.VolumeStreaming;
|
||||
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);
|
||||
|
||||
@@ -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 }
|
||||
@@ -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);
|
||||
|
||||
@@ -79,12 +79,10 @@ class Camera {
|
||||
}
|
||||
|
||||
getSnapshot() {
|
||||
const ret = Camera.createDefaultSnapshot();
|
||||
Camera.copySnapshot(ret, this.state);
|
||||
return ret;
|
||||
return Camera.copySnapshot(Camera.createDefaultSnapshot(), this.state);
|
||||
}
|
||||
|
||||
getFocus(target: Vec3, radius: number): Partial<Camera.Snapshot> {
|
||||
getFocus(target: Vec3, radius: number, up?: Vec3, dir?: Vec3): Partial<Camera.Snapshot> {
|
||||
const fov = this.state.fov
|
||||
const { width, height } = this.viewport
|
||||
const aspect = width / height
|
||||
@@ -92,6 +90,7 @@ class Camera {
|
||||
const targetDistance = Math.abs((radius / aspectFactor) / Math.sin(fov / 2))
|
||||
|
||||
Vec3.sub(this.deltaDirection, this.target, this.position)
|
||||
if (dir) Vec3.matchDirection(this.deltaDirection, dir, this.deltaDirection)
|
||||
Vec3.setMagnitude(this.deltaDirection, this.deltaDirection, targetDistance)
|
||||
Vec3.sub(this.newPosition, target, this.deltaDirection)
|
||||
|
||||
@@ -99,12 +98,13 @@ class Camera {
|
||||
state.target = Vec3.clone(target)
|
||||
state.radius = radius
|
||||
state.position = Vec3.clone(this.newPosition)
|
||||
if (up) Vec3.matchDirection(state.up, up, state.up)
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
focus(target: Vec3, radius: number, durationMs?: number) {
|
||||
if (radius > 0) this.setState(this.getFocus(target, radius), durationMs);
|
||||
focus(target: Vec3, radius: number, durationMs?: number, up?: Vec3, dir?: Vec3) {
|
||||
if (radius > 0) this.setState(this.getFocus(target, radius, up, dir), durationMs);
|
||||
}
|
||||
|
||||
project(out: Vec4, point: Vec3) {
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace Canvas3D {
|
||||
didRender = true
|
||||
}
|
||||
|
||||
return didRender && cameraChanged;
|
||||
return didRender;
|
||||
}
|
||||
|
||||
let forceNextDraw = false;
|
||||
|
||||
@@ -21,15 +21,15 @@ const M = ModifiersKeys
|
||||
const Trigger = Binding.Trigger
|
||||
|
||||
export const DefaultTrackballBindings = {
|
||||
dragRotate: Binding(Trigger(B.Flag.Primary, M.create()), 'Rotate the 3D scene by dragging using ${trigger}'),
|
||||
dragRotateZ: Binding(Trigger(B.Flag.Primary, M.create({ shift: true })), 'Rotate the 3D scene around the z-axis by dragging using ${trigger}'),
|
||||
dragPan: Binding(Trigger(B.Flag.Secondary, M.create()), 'Pan the 3D scene by dragging using ${trigger}'),
|
||||
dragRotate: Binding([Trigger(B.Flag.Primary, M.create())], 'Rotate the 3D scene by dragging using ${triggers}'),
|
||||
dragRotateZ: Binding([Trigger(B.Flag.Primary, M.create({ shift: true }))], 'Rotate the 3D scene around the z-axis by dragging using ${triggers}'),
|
||||
dragPan: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Pan the 3D scene by dragging using ${triggers}'),
|
||||
dragZoom: Binding.Empty,
|
||||
dragFocus: Binding(Trigger(B.Flag.Forth, M.create()), 'Focus the 3D scene by dragging using ${trigger}'),
|
||||
dragFocusZoom: Binding(Trigger(B.Flag.Auxilary, M.create()), 'Focus and zoom the 3D scene by dragging using ${trigger}'),
|
||||
dragFocus: Binding([Trigger(B.Flag.Forth, M.create())], 'Focus the 3D scene by dragging using ${triggers}'),
|
||||
dragFocusZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Focus and zoom the 3D scene by dragging using ${triggers}'),
|
||||
|
||||
scrollZoom: Binding(Trigger(B.Flag.Auxilary, M.create()), 'Zoom the 3D scene by scrolling using ${trigger}'),
|
||||
scrollFocus: Binding(Trigger(B.Flag.Auxilary, M.create({ shift: true })), 'Focus the 3D scene by scrolling using ${trigger}'),
|
||||
scrollZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Zoom the 3D scene by scrolling using ${triggers}'),
|
||||
scrollFocus: Binding([Trigger(B.Flag.Auxilary, M.create({ shift: true }))], 'Focus the 3D scene by scrolling using ${triggers}'),
|
||||
scrollFocusZoom: Binding.Empty,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
/** Set canvas size taking `devicePixelRatio` into account */
|
||||
export function setCanvasSize(canvas: HTMLCanvasElement, width: number, height: number) {
|
||||
canvas.width = window.devicePixelRatio * width
|
||||
canvas.height = window.devicePixelRatio * height
|
||||
canvas.width = Math.round(window.devicePixelRatio * width)
|
||||
canvas.height = Math.round(window.devicePixelRatio * height)
|
||||
Object.assign(canvas.style, { width: `${width}px`, height: `${height}px` })
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ function _canvasToBlob(canvas: HTMLCanvasElement, callback: BlobCallback, type?:
|
||||
const len = bin.length
|
||||
const len32 = len >> 2
|
||||
const a8 = new Uint8Array(len)
|
||||
const a32 = new Uint32Array( a8.buffer, 0, len32 )
|
||||
const a32 = new Uint32Array(a8.buffer, 0, len32)
|
||||
|
||||
let j = 0
|
||||
for (let i = 0; i < len32; ++i) {
|
||||
|
||||
@@ -343,9 +343,9 @@ function isIdentity(map: ArrayLike<number>, rowCount: number) {
|
||||
}
|
||||
|
||||
function columnView<T>(c: Column<T>, map: ArrayLike<number>, checkIdentity: boolean): Column<T> {
|
||||
if (!c.isDefined) return c;
|
||||
if (!c.isDefined || c.rowCount === 0) return c;
|
||||
if (checkIdentity && isIdentity(map, c.rowCount)) return c;
|
||||
if (!!c.__array) return arrayView(c, map);
|
||||
if (!!c.__array && typeof c.value(0) === typeof c.__array[0]) return arrayView(c, map);
|
||||
return viewFull(c, map);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ namespace UniqueArray {
|
||||
array[array.length] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function has<K, T>({ keys }: UniqueArray<K, T>, key: K) {
|
||||
return keys.has(key);
|
||||
}
|
||||
}
|
||||
|
||||
export { UniqueArray }
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
@@ -81,6 +81,13 @@ describe('ordered set', () => {
|
||||
expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([12, 13, 16]))).toBe(false);
|
||||
});
|
||||
|
||||
it('isSubsetIS', () => {
|
||||
expect(OrderedSet.isSubset(
|
||||
Interval.ofRange(1271, 1295),
|
||||
OrderedSet.ofSortedArray([1271, 1272, 1274, 1275, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294])
|
||||
)).toBe(true);
|
||||
});
|
||||
|
||||
it('access/membership', () => {
|
||||
expect(OrderedSet.has(empty, 10)).toBe(false);
|
||||
expect(OrderedSet.indexOf(empty, 10)).toBe(-1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
@@ -65,6 +65,90 @@ describe('sortedArray', () => {
|
||||
|
||||
test('intersectionSize', SortedArray.intersectionSize(a1234, a2468), 2);
|
||||
|
||||
// console.log(Interval.findPredecessorIndexInInterval(Interval.ofBounds(0, 3), 2, Interval.ofBounds(0, 3)))
|
||||
// console.log(SortedArray.findPredecessorIndexInInterval(SortedArray.ofSortedArray([0, 1, 2]), 2, Interval.ofBounds(0, 3)))
|
||||
it('union1', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 836, 837, 838, 839, 840, 841, 842, 843]),
|
||||
SortedArray.ofSortedArray([835])
|
||||
),
|
||||
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843])
|
||||
)
|
||||
})
|
||||
|
||||
it('union2', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([830, 832, 833]),
|
||||
SortedArray.ofSortedArray([831])
|
||||
),
|
||||
SortedArray.ofSortedArray([830, 831, 832, 833])
|
||||
)
|
||||
})
|
||||
|
||||
it('union3ab', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835]),
|
||||
SortedArray.ofSortedArray([836, 837, 838, 839, 840, 841, 842, 843])
|
||||
),
|
||||
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843])
|
||||
)
|
||||
})
|
||||
|
||||
it('union3ba', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([836, 837, 838, 839, 840, 841, 842, 843]),
|
||||
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835])
|
||||
),
|
||||
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843])
|
||||
)
|
||||
})
|
||||
|
||||
it('union4', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([1, 3, 5, 7, 9]),
|
||||
SortedArray.ofSortedArray([2, 4, 6, 8])
|
||||
),
|
||||
SortedArray.ofSortedArray([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
)
|
||||
})
|
||||
|
||||
it('union5', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([2, 3, 4, 20, 21, 22]),
|
||||
SortedArray.ofSortedArray([10, 11, 12])
|
||||
),
|
||||
SortedArray.ofSortedArray([2, 3, 4, 10, 11, 12, 20, 21, 22])
|
||||
)
|
||||
})
|
||||
|
||||
it('union6', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([768, 769, 770, 771, 772, 773, 774, 775, 776, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819]),
|
||||
SortedArray.ofSortedArray([1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758])
|
||||
),
|
||||
SortedArray.ofSortedArray([768, 769, 770, 771, 772, 773, 774, 775, 776, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819])
|
||||
)
|
||||
})
|
||||
|
||||
it('union7', () => {
|
||||
compareArrays(
|
||||
SortedArray.union(
|
||||
SortedArray.ofSortedArray([3766, 3767, 3768, 3770, 3773, 3780, 3783, 3787, 3797]),
|
||||
SortedArray.ofSortedArray([3769, 3790, 3794])
|
||||
),
|
||||
SortedArray.ofSortedArray([3766, 3767, 3768, 3769, 3770, 3773, 3780, 3783, 3787, 3790, 3794, 3797])
|
||||
)
|
||||
})
|
||||
|
||||
it('isSubset', () => {
|
||||
expect(SortedArray.isSubset(
|
||||
SortedArray.ofSortedArray([1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295]),
|
||||
SortedArray.ofSortedArray([1271, 1272, 1274, 1275, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294])
|
||||
)).toBe(true);
|
||||
})
|
||||
});
|
||||
@@ -126,7 +126,7 @@ function isSubsetIS(a: I, b: S) {
|
||||
const minA = I.min(a), maxA = I.max(a);
|
||||
if (maxA - minA + 1 === 0) return false;
|
||||
const minB = S.min(b), maxB = S.max(b);
|
||||
return minB >= minA && maxA <= maxB;
|
||||
return minB >= minA && maxB <= maxA;
|
||||
}
|
||||
|
||||
function areRangesIntersecting(a: OrderedSetImpl, b: OrderedSetImpl) {
|
||||
|
||||
@@ -171,28 +171,30 @@ export function isSubset(a: Nums, b: Nums) {
|
||||
return equal === lenB;
|
||||
}
|
||||
|
||||
export function union(a: Nums, b: Nums) {
|
||||
export function union(a: Nums, b: Nums): Nums {
|
||||
if (a === b) return a;
|
||||
|
||||
const lenA = a.length, lenB = b.length;
|
||||
if (lenA === 0) return b;
|
||||
if (lenB === 0) return a;
|
||||
if (a[0] > b[0]) return union(b, a);
|
||||
|
||||
const { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b);
|
||||
const commonCount = getCommonCount(a, b, startI, startJ, endI, endJ);
|
||||
|
||||
const lenA = a.length, lenB = b.length;
|
||||
// A === B || B is subset of A ==> A
|
||||
if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return a;
|
||||
// A is subset of B ===> B
|
||||
if (commonCount === lenA) return b;
|
||||
|
||||
const indices = new Int32Array(lenA + lenB - commonCount);
|
||||
let offset = 0;
|
||||
let i = 0, j = 0, offset = 0;
|
||||
|
||||
// insert the "prefixes"
|
||||
for (let k = 0; k < startI; k++) indices[offset++] = a[k];
|
||||
for (let k = 0; k < startJ; k++) indices[offset++] = b[k];
|
||||
for (i = 0; i < startI; i++) indices[offset++] = a[i];
|
||||
while (j < endJ && a[startI] > b[j]) indices[offset++] = b[j++];
|
||||
|
||||
// insert the common part
|
||||
let i = startI;
|
||||
let j = startJ;
|
||||
while (i < endI && j < endJ) {
|
||||
const x = a[i], y = b[j];
|
||||
if (x < y) { indices[offset++] = x; i++; }
|
||||
@@ -200,6 +202,10 @@ export function union(a: Nums, b: Nums) {
|
||||
else { indices[offset++] = x; i++; j++; }
|
||||
}
|
||||
|
||||
// insert the remaining common part
|
||||
for (; i < endI; i++) indices[offset++] = a[i];
|
||||
for (; j < endJ; j++) indices[offset++] = b[j];
|
||||
|
||||
// insert the "tail"
|
||||
for (; i < lenA; i++) indices[offset++] = a[i];
|
||||
for (; j < lenB; j++) indices[offset++] = b[j];
|
||||
|
||||
@@ -26,8 +26,7 @@ function setCylinderMat(m: Mat4, start: Vec3, dir: Vec3, length: number) {
|
||||
Vec3.add(tmpCylinderCenter, start, tmpCylinderMatDir)
|
||||
// ensure the direction used to create the rotation is always pointing in the same
|
||||
// direction so the triangles of adjacent cylinder will line up
|
||||
Vec3.copy(tmpUp, up)
|
||||
if (Vec3.dot(tmpCylinderMatDir, tmpUp) < 0) Vec3.scale(tmpUp, tmpUp, -1)
|
||||
Vec3.matchDirection(tmpUp, up, tmpCylinderMatDir)
|
||||
Vec3.makeRotation(m, tmpUp, tmpCylinderMatDir)
|
||||
return Mat4.setTranslation(m, tmpCylinderCenter)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,12 @@ export function Pyramid(points: ArrayLike<number>): Primitive {
|
||||
return builder.getPrimitive()
|
||||
}
|
||||
|
||||
let triangularPyramid: Primitive
|
||||
export function TriangularPyramid() {
|
||||
if (!triangularPyramid) triangularPyramid = Pyramid(polygon(3, true))
|
||||
return triangularPyramid
|
||||
}
|
||||
|
||||
let octagonalPyramid: Primitive
|
||||
export function OctagonalPyramid() {
|
||||
if (!octagonalPyramid) octagonalPyramid = Pyramid(polygon(8, true))
|
||||
|
||||
@@ -189,16 +189,7 @@ const glsl300VertPrefix = `#version 300 es
|
||||
#define texture2D texture
|
||||
`
|
||||
|
||||
const glsl300FragPrefix = `#version 300 es
|
||||
layout(location = 0) out highp vec4 out_FragData0;
|
||||
layout(location = 1) out highp vec4 out_FragData1;
|
||||
layout(location = 2) out highp vec4 out_FragData2;
|
||||
layout(location = 3) out highp vec4 out_FragData3;
|
||||
layout(location = 4) out highp vec4 out_FragData4;
|
||||
layout(location = 5) out highp vec4 out_FragData5;
|
||||
layout(location = 6) out highp vec4 out_FragData6;
|
||||
layout(location = 7) out highp vec4 out_FragData7;
|
||||
|
||||
const glsl300FragPrefixCommon = `
|
||||
#define varying in
|
||||
#define texture2D texture
|
||||
#define texture2DLodEXT textureLod
|
||||
@@ -211,16 +202,29 @@ layout(location = 7) out highp vec4 out_FragData7;
|
||||
#define requiredDrawBuffers
|
||||
`
|
||||
|
||||
function getGlsl300FragPrefix(gl: WebGL2RenderingContext, extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
|
||||
const prefix = [ '#version 300 es' ]
|
||||
if (extensions.drawBuffers) {
|
||||
const maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS) as number
|
||||
for (let i = 0, il = maxDrawBuffers; i < il; ++i) {
|
||||
prefix.push(`layout(location = ${i}) out highp vec4 out_FragData${i};`)
|
||||
}
|
||||
}
|
||||
prefix.push(glsl300FragPrefixCommon)
|
||||
return prefix.join('\n') + '\n'
|
||||
}
|
||||
|
||||
function transformGlsl300Frag(frag: string) {
|
||||
return frag.replace(/gl_FragData\[([0-7])\]/g, 'out_FragData$1')
|
||||
return frag.replace(/gl_FragData\[([0-9]+)\]/g, 'out_FragData$1')
|
||||
}
|
||||
|
||||
export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
|
||||
const webgl2 = isWebGL2(gl)
|
||||
const header = getDefinesCode(defines)
|
||||
const vertPrefix = webgl2 ? glsl300VertPrefix : ''
|
||||
const fragPrefix = webgl2 ? glsl300FragPrefix : getGlsl100FragPrefix(extensions, shaders.extensions)
|
||||
const frag = webgl2 ? transformGlsl300Frag(shaders.frag) : shaders.frag
|
||||
const vertPrefix = isWebGL2(gl) ? glsl300VertPrefix : ''
|
||||
const fragPrefix = isWebGL2(gl)
|
||||
? getGlsl300FragPrefix(gl, extensions, shaders.extensions)
|
||||
: getGlsl100FragPrefix(extensions, shaders.extensions)
|
||||
const frag = isWebGL2(gl) ? transformGlsl300Frag(shaders.frag) : shaders.frag
|
||||
return {
|
||||
id: shaderCodeId(),
|
||||
vert: `${vertPrefix}${header}${shaders.vert}`,
|
||||
|
||||
@@ -23,7 +23,7 @@ attribute mat4 aTransform;
|
||||
attribute float aInstance;
|
||||
attribute float aGroup;
|
||||
|
||||
#ifndef dFlatShaded
|
||||
#if !defined(dFlatShaded) || !defined(enabledStandardDerivatives)
|
||||
#ifdef dGeoTexture
|
||||
uniform sampler2D tNormal;
|
||||
#else
|
||||
@@ -38,7 +38,7 @@ void main(){
|
||||
#include assign_marker_varying
|
||||
#include assign_position
|
||||
|
||||
#ifndef dFlatShaded
|
||||
#if !defined(dFlatShaded) || !defined(enabledStandardDerivatives)
|
||||
#ifdef dGeoTexture
|
||||
vec3 normal = readFromTexture(tNormal, aGroup, uGeoTexDim).xyz;
|
||||
#else
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture } from './compat';
|
||||
import { isDebugMode } from '../../mol-util/debug';
|
||||
|
||||
export type WebGLExtensions = {
|
||||
instancedArrays: COMPAT_instanced_arrays
|
||||
@@ -37,43 +38,45 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
|
||||
}
|
||||
|
||||
const standardDerivatives = getStandardDerivatives(gl)
|
||||
if (standardDerivatives === null) {
|
||||
// TODO handle non-support downstream (e.g. no flat shading)
|
||||
// throw new Error('Could not find support for "standard_derivatives"')
|
||||
if (isDebugMode && standardDerivatives === null) {
|
||||
// - non-support handled downstream (flat shading option is ignored)
|
||||
// - can't be a required extension because it is not supported by `headless-gl`
|
||||
console.log('Could not find support for "standard_derivatives"')
|
||||
}
|
||||
const textureFloatLinear = getTextureFloatLinear(gl)
|
||||
if (textureFloatLinear === null) {
|
||||
if (isDebugMode && textureFloatLinear === null) {
|
||||
// TODO handle non-support downstream (no gpu gaussian calc, no gpu mc???)
|
||||
// throw new Error('Could not find support for "texture_float_linear"')
|
||||
// - can't be a required extension because it is not supported by `headless-gl`
|
||||
console.log('Could not find support for "texture_float_linear"')
|
||||
}
|
||||
const depthTexture = getDepthTexture(gl)
|
||||
if (depthTexture === null) {
|
||||
if (isDebugMode && depthTexture === null) {
|
||||
console.log('Could not find support for "depth_texture"')
|
||||
}
|
||||
const blendMinMax = getBlendMinMax(gl)
|
||||
if (blendMinMax === null) {
|
||||
if (isDebugMode && blendMinMax === null) {
|
||||
// TODO handle non-support downstream (e.g. no gpu gaussian calc)
|
||||
// - can't be a required extension because it is not supported by `headless-gl`
|
||||
console.log('Could not find support for "blend_minmax"')
|
||||
}
|
||||
const vertexArrayObject = getVertexArrayObject(gl)
|
||||
if (vertexArrayObject === null) {
|
||||
if (isDebugMode && vertexArrayObject === null) {
|
||||
console.log('Could not find support for "vertex_array_object"')
|
||||
}
|
||||
const fragDepth = getFragDepth(gl)
|
||||
if (fragDepth === null) {
|
||||
if (isDebugMode && fragDepth === null) {
|
||||
console.log('Could not find support for "frag_depth"')
|
||||
}
|
||||
const colorBufferFloat = getColorBufferFloat(gl)
|
||||
if (colorBufferFloat === null) {
|
||||
if (isDebugMode && colorBufferFloat === null) {
|
||||
console.log('Could not find support for "color_buffer_float"')
|
||||
}
|
||||
const drawBuffers = getDrawBuffers(gl)
|
||||
if (drawBuffers === null) {
|
||||
if (isDebugMode && drawBuffers === null) {
|
||||
console.log('Could not find support for "draw_buffers"')
|
||||
}
|
||||
const shaderTextureLod = getShaderTextureLod(gl)
|
||||
if (shaderTextureLod === null) {
|
||||
if (isDebugMode && shaderTextureLod === null) {
|
||||
console.log('Could not find support for "shader_texture_lod"')
|
||||
}
|
||||
|
||||
|
||||
17
src/mol-io/reader/_spec/common.spec.ts
Normal file
17
src/mol-io/reader/_spec/common.spec.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { parseFloat as fastParseFloat, parseInt as fastParseInt } from '../../../mol-io/reader/common/text/number-parser';
|
||||
|
||||
describe('common', () => {
|
||||
it('number-parser fastParseFloat', () => {
|
||||
expect(fastParseFloat('11.0829(23)', 0, 11)).toBe(11.0829)
|
||||
});
|
||||
|
||||
it('number-parser fastParseInt', () => {
|
||||
expect(fastParseInt('11(23)', 0, 11)).toBe(11)
|
||||
});
|
||||
});
|
||||
@@ -14,6 +14,7 @@ import { CCD_Schema, CCD_Database } from './cif/schema/ccd'
|
||||
import { BIRD_Schema, BIRD_Database } from './cif/schema/bird'
|
||||
import { dic_Schema, dic_Database } from './cif/schema/dic'
|
||||
import { DensityServer_Data_Schema, DensityServer_Data_Database } from './cif/schema/density-server'
|
||||
import { cifCore_Database, cifCore_Schema, cifCore_Aliases } from './cif/schema/cif-core'
|
||||
|
||||
export const CIF = {
|
||||
parse: (data: string|Uint8Array) => typeof data === 'string' ? parseText(data) : parseBinary(data),
|
||||
@@ -26,7 +27,8 @@ export const CIF = {
|
||||
CCD: (frame: CifFrame) => toDatabase<CCD_Schema, CCD_Database>(CCD_Schema, frame),
|
||||
BIRD: (frame: CifFrame) => toDatabase<BIRD_Schema, BIRD_Database>(BIRD_Schema, frame),
|
||||
dic: (frame: CifFrame) => toDatabase<dic_Schema, dic_Database>(dic_Schema, frame),
|
||||
densityServer: (frame: CifFrame) => toDatabase<DensityServer_Data_Schema, DensityServer_Data_Database>(DensityServer_Data_Schema, frame)
|
||||
cifCore: (frame: CifFrame) => toDatabase<cifCore_Schema, cifCore_Database>(cifCore_Schema, frame, cifCore_Aliases),
|
||||
densityServer: (frame: CifFrame) => toDatabase<DensityServer_Data_Schema, DensityServer_Data_Database>(DensityServer_Data_Schema, frame),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* 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>
|
||||
@@ -23,23 +23,31 @@ export function CifFile(blocks: ArrayLike<CifBlock>, name?: string): CifFile {
|
||||
|
||||
export interface CifFrame {
|
||||
readonly header: string,
|
||||
// Category names stored separately so that the ordering can be preserved.
|
||||
/** Category names, stored separately so that the ordering can be preserved. */
|
||||
readonly categoryNames: ReadonlyArray<string>,
|
||||
readonly categories: CifCategories
|
||||
}
|
||||
|
||||
export interface CifBlock extends CifFrame {
|
||||
readonly saveFrames: CifFrame[]
|
||||
getField(name: string): CifField | undefined
|
||||
}
|
||||
|
||||
export function CifBlock(categoryNames: string[], categories: CifCategories, header: string, saveFrames: CifFrame[] = []): CifBlock {
|
||||
return { categoryNames, header, categories, saveFrames };
|
||||
return {
|
||||
categoryNames, header, categories, saveFrames,
|
||||
getField(name: string) {
|
||||
const [ category, field ] = name.split('.')
|
||||
return categories[category].getField(field || '')
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function CifSafeFrame(categoryNames: string[], categories: CifCategories, header: string): CifFrame {
|
||||
export function CifSaveFrame(categoryNames: string[], categories: CifCategories, header: string): CifFrame {
|
||||
return { categoryNames, header, categories };
|
||||
}
|
||||
|
||||
export type CifAliases = { readonly [name: string]: string[] }
|
||||
export type CifCategories = { readonly [name: string]: CifCategory }
|
||||
|
||||
export interface CifCategory {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* 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>
|
||||
@@ -10,16 +10,31 @@ import { Tensor } from '../../../mol-math/linear-algebra'
|
||||
import { arrayEqual } from '../../../mol-util'
|
||||
import * as Data from './data-model'
|
||||
|
||||
export function toDatabaseCollection<Schema extends Database.Schema>(schema: Schema, file: Data.CifFile): DatabaseCollection<Schema> {
|
||||
export namespace FieldPath {
|
||||
export function canonical(path: string) {
|
||||
return path.replace('.', '_').replace(/\[/, '_').replace(/(\[|\])/g, '')
|
||||
}
|
||||
|
||||
export function equal(pathA: string, pathB: string) {
|
||||
return canonical(pathA) === canonical(pathB)
|
||||
}
|
||||
|
||||
export function create(category: string, field: string, asCanonical = false) {
|
||||
const p = `${category}${field ? `.${field}` : ''}`
|
||||
return asCanonical ? canonical(p) : p
|
||||
}
|
||||
}
|
||||
|
||||
export function toDatabaseCollection<Schema extends Database.Schema>(schema: Schema, file: Data.CifFile, aliases?: Data.CifAliases): DatabaseCollection<Schema> {
|
||||
const dbc: DatabaseCollection<Schema> = {}
|
||||
for (const data of file.blocks) {
|
||||
dbc[data.header] = toDatabase(schema, data)
|
||||
dbc[data.header] = toDatabase(schema, data, aliases)
|
||||
}
|
||||
return dbc;
|
||||
}
|
||||
|
||||
export function toDatabase<Schema extends Database.Schema, Frame extends Database<Schema> = Database<Schema>>(schema: Schema, frame: Data.CifFrame): Frame {
|
||||
return createDatabase(schema, frame) as Frame;
|
||||
export function toDatabase<Schema extends Database.Schema, Frame extends Database<Schema> = Database<Schema>>(schema: Schema, frame: Data.CifFrame, aliases?: Data.CifAliases): Frame {
|
||||
return createDatabase(schema, frame, aliases) as Frame;
|
||||
}
|
||||
|
||||
export function toTable<Schema extends Table.Schema, R extends Table<Schema> = Table<Schema>>(schema: Schema, category: Data.CifCategory): R {
|
||||
@@ -51,7 +66,7 @@ function createColumn<T>(schema: Column.Schema, field: Data.CifField, value: (ro
|
||||
};
|
||||
}
|
||||
|
||||
function createListColumn<T extends number|string>(schema: Column.Schema.List<T>, category: Data.CifCategory, key: string): Column<(number|string)[]> {
|
||||
function createListColumn<T extends number | string>(schema: Column.Schema.List<T>, category: Data.CifCategory, key: string): Column<(number | string)[]> {
|
||||
const separator = schema.separator;
|
||||
const itemParse = schema.itemParse;
|
||||
|
||||
@@ -134,15 +149,62 @@ class CategoryTable implements Table<any> { // tslint:disable-line:class-name
|
||||
}
|
||||
}
|
||||
|
||||
function createDatabase(schema: Database.Schema, frame: Data.CifFrame): Database<any> {
|
||||
function createDatabase(schema: Database.Schema, frame: Data.CifFrame, aliases?: Data.CifAliases): Database<any> {
|
||||
const tables = Object.create(null);
|
||||
for (const k of Object.keys(schema)) {
|
||||
tables[k] = createTable(k, (schema as any)[k], frame);
|
||||
tables[k] = createTable(k, schema[k], frame, aliases);
|
||||
}
|
||||
return Database.ofTables(frame.header, schema, tables);
|
||||
}
|
||||
|
||||
function createTable(key: string, schema: Table.Schema, frame: Data.CifFrame) {
|
||||
const cat = frame.categories[key];
|
||||
type FlatFrame = { [k: string]: Data.CifField }
|
||||
|
||||
function flattenFrame(frame: Data.CifFrame): FlatFrame {
|
||||
const flatFrame = Object.create(null)
|
||||
for (const c of Object.keys(frame.categories)) {
|
||||
for (const f of frame.categories[c].fieldNames) {
|
||||
const p = FieldPath.create(c, f, true)
|
||||
flatFrame[p] = frame.categories[c].getField(f)
|
||||
}
|
||||
}
|
||||
return flatFrame
|
||||
}
|
||||
|
||||
function getField(field: string, category: string, flatFrame: FlatFrame, aliases?: Data.CifAliases) {
|
||||
const path = FieldPath.create(category, field)
|
||||
const canonicalPath = FieldPath.canonical(path)
|
||||
if (canonicalPath in flatFrame) return flatFrame[canonicalPath]
|
||||
if (aliases && path in aliases) {
|
||||
for (const aliased of aliases[path]) {
|
||||
const canonicalAliased = FieldPath.canonical(aliased)
|
||||
if (canonicalAliased in flatFrame) return flatFrame[canonicalAliased]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createTable(key: string, schema: Table.Schema, frame: Data.CifFrame, aliases?: Data.CifAliases) {
|
||||
let cat = frame.categories[key];
|
||||
if (aliases) {
|
||||
const flatFrame = flattenFrame(frame)
|
||||
const fields: { [k: string]: Data.CifField } = Object.create(null)
|
||||
const fieldNames: string[] = []
|
||||
let rowCount = 0
|
||||
for (const k of Object.keys(schema)) {
|
||||
const field = getField(k, key, flatFrame, aliases)
|
||||
if (field) {
|
||||
fields[k] = field
|
||||
fieldNames.push(k)
|
||||
rowCount = field.rowCount
|
||||
}
|
||||
}
|
||||
cat = {
|
||||
rowCount,
|
||||
name: key,
|
||||
fieldNames: [...fieldNames],
|
||||
getField(name: string) {
|
||||
return fields[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
return new CategoryTable(cat || Data.CifCategory.empty(key), schema, !!cat);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.314, IHM 1.01, CARB draft.
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.318, IHM 1.04, CARB draft.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.314, IHM 1.01, CARB draft.
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.318, IHM 1.04, CARB draft.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
637
src/mol-io/reader/cif/schema/cif-core.ts
Normal file
637
src/mol-io/reader/cif/schema/cif-core.ts
Normal file
@@ -0,0 +1,637 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'cifCore' schema file. Dictionary versions: CifCore 3.0.11.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
import { Database, Column } from '../../../../mol-data/db'
|
||||
|
||||
import Schema = Column.Schema
|
||||
|
||||
const int = Schema.int;
|
||||
const float = Schema.float;
|
||||
const str = Schema.str;
|
||||
|
||||
export const cifCore_Schema = {
|
||||
/**
|
||||
* The CATEGORY of data items used to describe the parameters of
|
||||
* the crystal unit cell and their measurement.
|
||||
*/
|
||||
cell: {
|
||||
/**
|
||||
* The number of the formula units in the unit cell as specified
|
||||
* by _chemical_formula.structural, _chemical_formula.moiety or
|
||||
* _chemical_formula.sum.
|
||||
*/
|
||||
formula_units_Z: int,
|
||||
/**
|
||||
* Volume of the crystal unit cell.
|
||||
*/
|
||||
volume: float,
|
||||
/**
|
||||
* The angle between the bounding cell axes.
|
||||
*/
|
||||
angle_alpha: float,
|
||||
/**
|
||||
* The angle between the bounding cell axes.
|
||||
*/
|
||||
angle_beta: float,
|
||||
/**
|
||||
* The angle between the bounding cell axes.
|
||||
*/
|
||||
angle_gamma: float,
|
||||
/**
|
||||
* The length of each cell axis.
|
||||
*/
|
||||
length_a: float,
|
||||
/**
|
||||
* The length of each cell axis.
|
||||
*/
|
||||
length_b: float,
|
||||
/**
|
||||
* The length of each cell axis.
|
||||
*/
|
||||
length_c: float,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items which describe the composition and
|
||||
* chemical properties of the compound under study. The formula data
|
||||
* items must be consistent with the density, unit-cell and Z values.
|
||||
*/
|
||||
chemical: {
|
||||
/**
|
||||
* The temperature at which a crystalline solid changes to a liquid.
|
||||
*/
|
||||
melting_point: float,
|
||||
/**
|
||||
* Trivial name by which the compound is commonly known.
|
||||
*/
|
||||
name_common: str,
|
||||
/**
|
||||
* IUPAC or Chemical Abstracts full name of compound.
|
||||
*/
|
||||
name_systematic: str,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items which specify the composition and chemical
|
||||
* properties of the compound. The formula data items must agree
|
||||
* with those that specify the density, unit-cell and Z values.
|
||||
*
|
||||
* The following rules apply to the construction of the data items
|
||||
* _chemical_formula.analytical, *.structural and *.sum. For the
|
||||
* data item *.moiety the formula construction is broken up into
|
||||
* residues or moieties, i.e. groups of atoms that form a molecular
|
||||
* unit or molecular ion. The rules given below apply within each
|
||||
* moiety but different requirements apply to the way that moieties
|
||||
* are connected (see _chemical_formula.moiety).
|
||||
*
|
||||
* 1. Only recognized element symbols may be used.
|
||||
*
|
||||
* 2. Each element symbol is followed by a 'count' number. A count of
|
||||
* '1' may be omitted.
|
||||
*
|
||||
* 3. A space or parenthesis must separate each cluster of (element
|
||||
* symbol + count).
|
||||
*
|
||||
* 4. Where a group of elements is enclosed in parentheses, the
|
||||
* multiplier for the group must follow the closing parentheses.
|
||||
* That is, all element and group multipliers are assumed to be
|
||||
* printed as subscripted numbers. [An exception to this rule
|
||||
* exists for *.moiety formulae where pre- and post-multipliers
|
||||
* are permitted for molecular units].
|
||||
*
|
||||
* 5. Unless the elements are ordered in a manner that corresponds to
|
||||
* their chemical structure, as in _chemical_formula.structural,
|
||||
* the order of the elements within any group or moiety
|
||||
* depends on whether or not carbon is present. If carbon is
|
||||
* present, the order should be: C, then H, then the other
|
||||
* elements in alphabetical order of their symbol. If carbon is
|
||||
* not present, the elements are listed purely in alphabetic order
|
||||
* of their symbol. This is the 'Hill' system used by Chemical
|
||||
* Abstracts. This ordering is used in _chemical_formula.moiety
|
||||
* and _chemical_formula.sum.
|
||||
*
|
||||
* _chemical_formula.iupac '[Mo (C O)4 (C18 H33 P)2]'
|
||||
* _chemical_formula.moiety 'C40 H66 Mo O4 P2'
|
||||
* _chemical_formula.structural '((C O)4 (P (C6 H11)3)2)Mo'
|
||||
* _chemical_formula.sum 'C40 H66 Mo O4 P2'
|
||||
* _chemical_formula.weight 768.81
|
||||
*/
|
||||
chemical_formula: {
|
||||
/**
|
||||
* Formula with each discrete bonded residue or ion shown as a
|
||||
* separate moiety. See above CHEMICAL_FORMULA for rules
|
||||
* for writing chemical formulae. In addition to the general
|
||||
* formulae requirements, the following rules apply:
|
||||
* 1. Moieties are separated by commas ','.
|
||||
* 2. The order of elements within a moiety follows general rule
|
||||
* 5 in CHEMICAL_FORMULA.
|
||||
* 3. Parentheses are not used within moieties but may surround
|
||||
* a moiety. Parentheses may not be nested.
|
||||
* 4. Charges should be placed at the end of the moiety. The
|
||||
* Singlege '+' or '-' may be preceded by a numerical multiplier
|
||||
* and should be separated from the last (element symbol +
|
||||
* count) by a space. Pre- or post-multipliers may be used for
|
||||
* individual moieties.
|
||||
*/
|
||||
moiety: str,
|
||||
/**
|
||||
* Chemical formulae in which all discrete bonded residues and ions are
|
||||
* summed over the constituent elements, following the ordering given
|
||||
* in rule 5 of the CATEGORY description. Parentheses normally not used.
|
||||
*/
|
||||
sum: str,
|
||||
/**
|
||||
* Mass corresponding to the formulae _chemical_formula.structural,
|
||||
* *_iupac, *_moiety or *_sum and, together with the Z value and cell
|
||||
* parameters yield the density given as _exptl_crystal.density_diffrn.
|
||||
*/
|
||||
weight: float,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to specify space group
|
||||
* information about the crystal used in the diffraction measurements.
|
||||
*
|
||||
* Space-group types are identified by their number as listed in
|
||||
* International Tables for Crystallography Volume A, or by their
|
||||
* Schoenflies symbol. Specific settings of the space groups can
|
||||
* be identified by their Hall symbol, by specifying their
|
||||
* symmetry operations or generators, or by giving the
|
||||
* transformation that relates the specific setting to the
|
||||
* reference setting based on International Tables Volume A and
|
||||
* stored in this dictionary.
|
||||
*
|
||||
* The commonly used Hermann-Mauguin symbol determines the
|
||||
* space-group type uniquely but several different Hermann-Mauguin
|
||||
* symbols may refer to the same space-group type. A
|
||||
* Hermann-Mauguin symbol contains information on the choice of
|
||||
* the basis, but not on the choice of origin.
|
||||
*
|
||||
* Ref: International Tables for Crystallography (2002). Volume A,
|
||||
* Space-group symmetry, edited by Th. Hahn, 5th ed.
|
||||
* Dordrecht: Kluwer Academic Publishers.
|
||||
*/
|
||||
space_group: {
|
||||
/**
|
||||
* The name of the system of geometric crystal classes of space
|
||||
* groups (crystal system) to which the space group belongs.
|
||||
* Note that rhombohedral space groups belong to the
|
||||
* trigonal system.
|
||||
*/
|
||||
crystal_system: str,
|
||||
/**
|
||||
* The full international Hermann-Mauguin space-group symbol as
|
||||
* defined in Section 2.2.3 and given as the second item of the
|
||||
* second line of each of the space-group tables of Part 7 of
|
||||
* International Tables for Crystallography Volume A (2002).
|
||||
*
|
||||
* Each component of the space-group name is separated by a
|
||||
* space or an underscore character. The use of a space is
|
||||
* strongly recommended. The underscore is only retained
|
||||
* because it was used in old CIFs. It should not be used in
|
||||
* new CIFs.
|
||||
*
|
||||
* Subscripts should appear without special symbols. Bars should
|
||||
* be given as negative signs before the numbers to which they
|
||||
* apply. The commonly used Hermann-Mauguin symbol determines the
|
||||
* space-group type uniquely but a given space-group type may
|
||||
* be described by more than one Hermann-Mauguin symbol. The
|
||||
* space-group type is best described using
|
||||
* _space_group.IT_number or _space_group.name_Schoenflies. The
|
||||
* full international Hermann-Mauguin symbol contains information
|
||||
* about the choice of basis for monoclinic and orthorhombic
|
||||
* space groups but does not give information about the choice
|
||||
* of origin. To define the setting uniquely use
|
||||
* _space_group.name_Hall, or list the symmetry operations
|
||||
* or generators.
|
||||
*
|
||||
* Ref: International Tables for Crystallography (2002). Volume A,
|
||||
* Space-group symmetry, edited by Th. Hahn, 5th ed.
|
||||
* Dordrecht: Kluwer Academic Publishers.
|
||||
*/
|
||||
'name_H-M_full': str,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to describe symmetry equivalent sites
|
||||
* in the crystal unit cell.
|
||||
*/
|
||||
space_group_symop: {
|
||||
/**
|
||||
* A parsable string giving one of the symmetry operations of the
|
||||
* space group in algebraic form. If W is a matrix representation
|
||||
* of the rotational part of the symmetry operation defined by the
|
||||
* positions and signs of x, y and z, and w is a column of
|
||||
* translations defined by fractions, an equivalent position
|
||||
* X' is generated from a given position X by the equation
|
||||
*
|
||||
* X' = WX + w
|
||||
*
|
||||
* (Note: X is used to represent bold_italics_x in International
|
||||
* Tables for Crystallography Vol. A, Part 5)
|
||||
*
|
||||
* When a list of symmetry operations is given, it must contain
|
||||
* a complete set of coordinate representatives which generates
|
||||
* all the operations of the space group by the addition of
|
||||
* all primitive translations of the space group. Such
|
||||
* representatives are to be found as the coordinates of
|
||||
* the general-equivalent position in International Tables for
|
||||
* Crystallography Vol. A (2002), to which it is necessary to
|
||||
* add any centring translations shown above the
|
||||
* general-equivalent position.
|
||||
*
|
||||
* That is to say, it is necessary to list explicitly all the
|
||||
* symmetry operations required to generate all the atoms in
|
||||
* the unit cell defined by the setting used.
|
||||
*/
|
||||
operation_xyz: str,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to specify the geometry bonds in the
|
||||
* structural model as derived from the atomic sites.
|
||||
*/
|
||||
geom_bond: {
|
||||
/**
|
||||
* This label is a unique identifier for a particular site in the
|
||||
* asymmetric unit of the crystal unit cell.
|
||||
*/
|
||||
atom_site_label_1: str,
|
||||
/**
|
||||
* This label is a unique identifier for a particular site in the
|
||||
* asymmetric unit of the crystal unit cell.
|
||||
*/
|
||||
atom_site_label_2: str,
|
||||
/**
|
||||
* Intramolecular bond distance between the sites identified
|
||||
* by _geom_bond.id
|
||||
*/
|
||||
distance: float,
|
||||
/**
|
||||
* This code signals whether the angle is referred to in a
|
||||
* publication or should be placed in a table of significant angles.
|
||||
*/
|
||||
publ_flag: str,
|
||||
/**
|
||||
* The set of data items which specify the symmetry operation codes
|
||||
* which must be applied to the atom sites involved in the geometry angle.
|
||||
*
|
||||
* The symmetry code of each atom site as the symmetry-equivalent position
|
||||
* number 'n' and the cell translation number 'pqr'. These numbers are
|
||||
* combined to form the code 'n pqr' or n_pqr.
|
||||
*
|
||||
* The character string n_pqr is composed as follows:
|
||||
*
|
||||
* n refers to the symmetry operation that is applied to the
|
||||
* coordinates stored in _atom_site.fract_xyz. It must match a
|
||||
* number given in _symmetry_equiv.pos_site_id.
|
||||
*
|
||||
* p, q and r refer to the translations that are subsequently
|
||||
* applied to the symmetry transformed coordinates to generate
|
||||
* the atom used in calculating the angle. These translations
|
||||
* (x,y,z) are related to (p,q,r) by the relations
|
||||
* p = 5 + x
|
||||
* q = 5 + y
|
||||
* r = 5 + z
|
||||
*/
|
||||
site_symmetry_2: str,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to record details about the
|
||||
* creation and subsequent updating of the data block.
|
||||
*/
|
||||
audit: {
|
||||
/**
|
||||
* The digital object identifier (DOI) registered to identify
|
||||
* the data set publication represented by the current
|
||||
* datablock. This can be used as a unique identifier for
|
||||
* the datablock so long as the code used is a valid DOI
|
||||
* (i.e. begins with a valid publisher prefix assigned by a
|
||||
* Registration Agency and a suffix guaranteed to be unique
|
||||
* by the publisher) and has had its metadata deposited
|
||||
* with a DOI Registration Agency.
|
||||
*
|
||||
* A DOI is a unique character string identifying any
|
||||
* object of intellectual property. It provides a
|
||||
* persistent identifier for an object on a digital network
|
||||
* and permits the association of related current data in a
|
||||
* structured extensible way. A DOI is an implementation
|
||||
* of the Internet concepts of Uniform Resource Name and
|
||||
* Universal Resource Locator managed according to the
|
||||
* specifications of the International DOI Foundation (see
|
||||
* http://www.doi.org).
|
||||
*/
|
||||
block_doi: str,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items recording database deposition. These data items
|
||||
* are assigned by database managers and should only appear in a CIF if they
|
||||
* originate from that source.
|
||||
*/
|
||||
database_code: {
|
||||
/**
|
||||
* Deposition numbers assigned by the Cambridge Crystallographic
|
||||
* Data Centre (CCDC) to files containing structural information
|
||||
* archived by the CCDC.
|
||||
*/
|
||||
depnum_ccdc_archive: str,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to describe atom site information
|
||||
* used in crystallographic structure studies.
|
||||
*/
|
||||
atom_site: {
|
||||
/**
|
||||
* Code for type of atomic displacement parameters used for the site.
|
||||
*/
|
||||
adp_type: str,
|
||||
/**
|
||||
* A standard code to signal if the site coordinates have been
|
||||
* determined from the intensities or calculated from the geometry
|
||||
* of surrounding sites, or have been assigned dummy coordinates.
|
||||
*/
|
||||
calc_flag: str,
|
||||
/**
|
||||
* A code which identifies a cluster of atoms that show long range
|
||||
* positional disorder but are locally ordered. Within each such
|
||||
* cluster of atoms, _atom_site.disorder_group is used to identify
|
||||
* the sites that are simultaneously occupied. This field is only
|
||||
* needed if there is more than one cluster of disordered atoms
|
||||
* showing independent local order.
|
||||
*/
|
||||
disorder_assembly: str,
|
||||
/**
|
||||
* A code that identifies a group of positionally disordered atom
|
||||
* sites that are locally simultaneously occupied. Atoms that are
|
||||
* positionally disordered over two or more sites (e.g. the H
|
||||
* atoms of a methyl group that exists in two orientations) can
|
||||
* be assigned to two or more groups. Sites belonging to the same
|
||||
* group are simultaneously occupied, but those belonging to
|
||||
* different groups are not. A minus prefix (e.g. "-1") is used to
|
||||
* indicate sites disordered about a special position.
|
||||
*/
|
||||
disorder_group: str,
|
||||
/**
|
||||
* Atom site coordinates as fractions of the cell length values.
|
||||
*/
|
||||
fract_x: float,
|
||||
/**
|
||||
* Atom site coordinates as fractions of the cell length values.
|
||||
*/
|
||||
fract_y: float,
|
||||
/**
|
||||
* Atom site coordinates as fractions of the cell length values.
|
||||
*/
|
||||
fract_z: float,
|
||||
/**
|
||||
* This label is a unique identifier for a particular site in the
|
||||
* asymmetric unit of the crystal unit cell. It is made up of
|
||||
* components, _atom_site.label_component_0 to *_6, which may be
|
||||
* specified as separate data items. Component 0 usually matches one
|
||||
* of the specified _atom_type.symbol codes. This is not mandatory
|
||||
* if an _atom_site.type_symbol item is included in the atom site
|
||||
* list. The _atom_site.type_symbol always takes precedence over
|
||||
* an _atom_site.label in the identification of the atom type. The
|
||||
* label components 1 to 6 are optional, and normally only
|
||||
* components 0 and 1 are used. Note that components 0 and 1 are
|
||||
* concatenated, while all other components, if specified, are
|
||||
* separated by an underline character. Underline separators are
|
||||
* only used if higher-order components exist. If an intermediate
|
||||
* component is not used it may be omitted provided the underline
|
||||
* separators are inserted. For example the label 'C233__ggg' is
|
||||
* acceptable and represents the components C, 233, '', and ggg.
|
||||
* Each label may have a different number of components.
|
||||
*/
|
||||
label: str,
|
||||
/**
|
||||
* The fraction of the atom type present at this site.
|
||||
* The sum of the occupancies of all the atom types at this site
|
||||
* may not significantly exceed 1.0 unless it is a dummy site. The
|
||||
* value must lie in the 99.97% Gaussian confidence interval
|
||||
* -3u =< x =< 1 + 3u. The _enumeration.range of 0.0:1.0 is thus
|
||||
* correctly interpreted as meaning (0.0 - 3u) =< x =< (1.0 + 3u).
|
||||
*/
|
||||
occupancy: float,
|
||||
/**
|
||||
* A concatenated series of single-letter codes which indicate the
|
||||
* refinement restraints or constraints applied to this site. This
|
||||
* item should not be used. It has been replaced by
|
||||
* _atom_site.refinement_flags_posn, _adp and _occupancy. It is
|
||||
* retained in this dictionary only to provide compatibility with
|
||||
* legacy CIFs.
|
||||
*/
|
||||
refinement_flags: str,
|
||||
/**
|
||||
* The number of different sites that are generated by the
|
||||
* application of the space-group symmetry to the coordinates
|
||||
* given for this site. It is equal to the multiplicity given
|
||||
* for this Wyckoff site in International Tables for Cryst.
|
||||
* Vol. A (2002). It is equal to the multiplicity of the general
|
||||
* position divided by the order of the site symmetry given in
|
||||
* _atom_site.site_symmetry_order.
|
||||
*/
|
||||
site_symmetry_multiplicity: int,
|
||||
/**
|
||||
* A code to identify the atom specie(s) occupying this site.
|
||||
* This code must match a corresponding _atom_type.symbol. The
|
||||
* specification of this code is optional if component_0 of the
|
||||
* _atom_site.label is used for this purpose. See _atom_type.symbol.
|
||||
*/
|
||||
type_symbol: str,
|
||||
/**
|
||||
* Isotropic atomic displacement parameter, or equivalent isotropic
|
||||
* atomic displacement parameter, U(equiv), in angstroms squared,
|
||||
* calculated from anisotropic atomic displacement parameters.
|
||||
*
|
||||
* U(equiv) = (1/3) sum~i~[sum~j~(U^ij^ a*~i~ a*~j~ a~i~ a~j~)]
|
||||
*
|
||||
* a = the real-space cell lengths
|
||||
* a* = the reciprocal-space cell lengths
|
||||
* Ref: Fischer, R. X. & Tillmanns, E. (1988). Acta Cryst. C44, 775-776.
|
||||
*/
|
||||
U_iso_or_equiv: float,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to describe the anisotropic
|
||||
* thermal parameters of the atomic sites in a crystal structure.
|
||||
*/
|
||||
atom_site_aniso: {
|
||||
/**
|
||||
* Anisotropic atomic displacement parameters are usually looped in
|
||||
* a separate list. If this is the case, this code must match the
|
||||
* _atom_site.label of the associated atom in the atom coordinate
|
||||
* list and conform with the same rules described in _atom_site.label.
|
||||
*/
|
||||
label: str,
|
||||
/**
|
||||
* These are the standard anisotropic atomic displacement
|
||||
* components in angstroms squared which appear in the
|
||||
* structure factor term:
|
||||
*
|
||||
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
|
||||
*
|
||||
* h = the Miller indices
|
||||
* a* = the reciprocal-space cell lengths
|
||||
*
|
||||
* The unique elements of the real symmetric matrix are entered by row.
|
||||
*/
|
||||
U_11: float,
|
||||
/**
|
||||
* These are the standard anisotropic atomic displacement
|
||||
* components in angstroms squared which appear in the
|
||||
* structure factor term:
|
||||
*
|
||||
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
|
||||
*
|
||||
* h = the Miller indices
|
||||
* a* = the reciprocal-space cell lengths
|
||||
*
|
||||
* The unique elements of the real symmetric matrix are entered by row.
|
||||
*/
|
||||
U_12: float,
|
||||
/**
|
||||
* These are the standard anisotropic atomic displacement
|
||||
* components in angstroms squared which appear in the
|
||||
* structure factor term:
|
||||
*
|
||||
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
|
||||
*
|
||||
* h = the Miller indices
|
||||
* a* = the reciprocal-space cell lengths
|
||||
*
|
||||
* The unique elements of the real symmetric matrix are entered by row.
|
||||
*/
|
||||
U_13: float,
|
||||
/**
|
||||
* These are the standard anisotropic atomic displacement
|
||||
* components in angstroms squared which appear in the
|
||||
* structure factor term:
|
||||
*
|
||||
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
|
||||
*
|
||||
* h = the Miller indices
|
||||
* a* = the reciprocal-space cell lengths
|
||||
*
|
||||
* The unique elements of the real symmetric matrix are entered by row.
|
||||
*/
|
||||
U_22: float,
|
||||
/**
|
||||
* These are the standard anisotropic atomic displacement
|
||||
* components in angstroms squared which appear in the
|
||||
* structure factor term:
|
||||
*
|
||||
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
|
||||
*
|
||||
* h = the Miller indices
|
||||
* a* = the reciprocal-space cell lengths
|
||||
*
|
||||
* The unique elements of the real symmetric matrix are entered by row.
|
||||
*/
|
||||
U_23: float,
|
||||
/**
|
||||
* These are the standard anisotropic atomic displacement
|
||||
* components in angstroms squared which appear in the
|
||||
* structure factor term:
|
||||
*
|
||||
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
|
||||
*
|
||||
* h = the Miller indices
|
||||
* a* = the reciprocal-space cell lengths
|
||||
*
|
||||
* The unique elements of the real symmetric matrix are entered by row.
|
||||
*/
|
||||
U_33: float,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to describe atomic type information
|
||||
* used in crystallographic structure studies.
|
||||
*/
|
||||
atom_type: {
|
||||
/**
|
||||
* A description of the atom(s) designated by this atom type. In
|
||||
* most cases this will be the element name and oxidation state of
|
||||
* a single atom species. For disordered or nonstoichiometric
|
||||
* structures it will describe a combination of atom species.
|
||||
*/
|
||||
description: str,
|
||||
/**
|
||||
* The identity of the atom specie(s) representing this atom type.
|
||||
* Normally this code is the element symbol followed by the charge
|
||||
* if there is one. The symbol may be composed of any character except
|
||||
* an underline or a blank, with the proviso that digits designate an
|
||||
* oxidation state and must be followed by a + or - character.
|
||||
*/
|
||||
symbol: str,
|
||||
},
|
||||
/**
|
||||
* The CATEGORY of data items used to describe atomic scattering
|
||||
* information used in crystallographic structure studies.
|
||||
*/
|
||||
atom_type_scat: {
|
||||
/**
|
||||
* The imaginary component of the anomalous dispersion scattering factors
|
||||
* for this atom type and radiation by _diffrn_radiation_wavelength.value
|
||||
*/
|
||||
dispersion_imag: float,
|
||||
/**
|
||||
* The real component of the anomalous dispersion scattering factors
|
||||
* for this atom type and radiation by _diffrn_radiation_wavelength.value
|
||||
*/
|
||||
dispersion_real: float,
|
||||
/**
|
||||
* Reference to source of scattering factors used for this atom type.
|
||||
*/
|
||||
source: str,
|
||||
},
|
||||
}
|
||||
|
||||
export const cifCore_Aliases = {
|
||||
'space_group.name_H-M_full': [
|
||||
'symmetry_space_group_name_H-M',
|
||||
],
|
||||
'space_group_symop.operation_xyz': [
|
||||
'symmetry_equiv_pos_as_xyz',
|
||||
],
|
||||
'geom_bond.atom_site_label_1': [
|
||||
'geom_bond_atom_site_id_1',
|
||||
],
|
||||
'geom_bond.atom_site_label_2': [
|
||||
'geom_bond_atom_site_id_2',
|
||||
],
|
||||
'geom_bond.distance': [
|
||||
'geom_bond_dist',
|
||||
],
|
||||
'atom_site.adp_type': [
|
||||
'atom_site_thermal_displace_type',
|
||||
],
|
||||
'atom_site.label': [
|
||||
'atom_site_id',
|
||||
],
|
||||
'atom_site.site_symmetry_multiplicity': [
|
||||
'atom_site_symmetry_multiplicity',
|
||||
],
|
||||
'atom_site_aniso.label': [
|
||||
'atom_site_anisotrop_id',
|
||||
],
|
||||
'atom_site_aniso.U_11': [
|
||||
'atom_site_anisotrop_U_11',
|
||||
],
|
||||
'atom_site_aniso.U_12': [
|
||||
'atom_site_anisotrop_U_12',
|
||||
],
|
||||
'atom_site_aniso.U_13': [
|
||||
'atom_site_anisotrop_U_13',
|
||||
],
|
||||
'atom_site_aniso.U_22': [
|
||||
'atom_site_anisotrop_U_22',
|
||||
],
|
||||
'atom_site_aniso.U_23': [
|
||||
'atom_site_anisotrop_U_23',
|
||||
],
|
||||
'atom_site_aniso.U_33': [
|
||||
'atom_site_anisotrop_U_33',
|
||||
],
|
||||
}
|
||||
|
||||
export type cifCore_Schema = typeof cifCore_Schema;
|
||||
export interface cifCore_Database extends Database<cifCore_Schema> {}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.314, IHM 1.01, CARB draft.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.318, IHM 1.04, CARB draft.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
@@ -142,12 +142,12 @@ export const mmCIF_Schema = {
|
||||
*/
|
||||
id: int,
|
||||
/**
|
||||
* A component of the identifier for this atom site.
|
||||
* For further details, see the definition of the ATOM_SITE_ALT
|
||||
* category.
|
||||
*
|
||||
* This data item is a pointer to _atom_sites_alt.id in the
|
||||
* ATOM_SITES_ALT category.
|
||||
* A place holder to indicate alternate conformation. The alternate conformation
|
||||
* can be an entire polymer chain, or several residues or
|
||||
* partial residue (several atoms within one residue). If
|
||||
* an atom is provided in more than one position, then a
|
||||
* non-blank alternate location indicator must be used for
|
||||
* each of the atomic positions.
|
||||
*/
|
||||
label_alt_id: str,
|
||||
/**
|
||||
@@ -333,6 +333,50 @@ export const mmCIF_Schema = {
|
||||
*/
|
||||
fract_transf_vector: Vector(3),
|
||||
},
|
||||
/**
|
||||
* Data items in the AUDIT_AUTHOR category record details about
|
||||
* the author(s) of the data block.
|
||||
*/
|
||||
audit_author: {
|
||||
/**
|
||||
* The name of an author of this data block. If there are multiple
|
||||
* authors, _audit_author.name is looped with _audit_author.address.
|
||||
* The family name(s), followed by a comma and including any
|
||||
* dynastic components, precedes the first name(s) or initial(s).
|
||||
*/
|
||||
name: str,
|
||||
/**
|
||||
* This data item defines the order of the author's name in the
|
||||
* list of audit authors.
|
||||
*/
|
||||
pdbx_ordinal: int,
|
||||
/**
|
||||
* The Open Researcher and Contributor ID (ORCID).
|
||||
*/
|
||||
identifier_ORCID: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the AUDIT_CONFORM category describe the
|
||||
* dictionary versions against which the data names appearing in
|
||||
* the current data block are conformant.
|
||||
*/
|
||||
audit_conform: {
|
||||
/**
|
||||
* A file name or uniform resource locator (URL) for the
|
||||
* dictionary to which the current data block conforms.
|
||||
*/
|
||||
dict_location: str,
|
||||
/**
|
||||
* The string identifying the highest-level dictionary defining
|
||||
* data names used in this file.
|
||||
*/
|
||||
dict_name: str,
|
||||
/**
|
||||
* The version number of the dictionary to which the current
|
||||
* data block conforms.
|
||||
*/
|
||||
dict_version: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the CELL category record details about the
|
||||
* crystallographic cell parameters.
|
||||
@@ -499,6 +543,143 @@ export const mmCIF_Schema = {
|
||||
*/
|
||||
pdbx_aromatic_flag: Aliased<'Y' | 'N'>(str),
|
||||
},
|
||||
/**
|
||||
* Data items in the CITATION category record details about the
|
||||
* literature cited as being relevant to the contents of the data
|
||||
* block.
|
||||
*/
|
||||
citation: {
|
||||
/**
|
||||
* The name of the publisher of the citation; relevant
|
||||
* for books or book chapters.
|
||||
*/
|
||||
book_publisher: str,
|
||||
/**
|
||||
* The country/region of publication; relevant for books
|
||||
* and book chapters.
|
||||
*/
|
||||
country: str,
|
||||
/**
|
||||
* The value of _citation.id must uniquely identify a record in the
|
||||
* CITATION list.
|
||||
*
|
||||
* The _citation.id 'primary' should be used to indicate the
|
||||
* citation that the author(s) consider to be the most pertinent to
|
||||
* the contents of the data block.
|
||||
*
|
||||
* Note that this item need not be a number; it can be any unique
|
||||
* identifier.
|
||||
*/
|
||||
id: str,
|
||||
/**
|
||||
* Abbreviated name of the cited journal as given in the
|
||||
* Chemical Abstracts Service Source Index.
|
||||
*/
|
||||
journal_abbrev: str,
|
||||
/**
|
||||
* The American Society for Testing and Materials (ASTM) code
|
||||
* assigned to the journal cited (also referred to as the CODEN
|
||||
* designator of the Chemical Abstracts Service); relevant for
|
||||
* journal articles.
|
||||
*/
|
||||
journal_id_ASTM: str,
|
||||
/**
|
||||
* The Cambridge Structural Database (CSD) code assigned to the
|
||||
* journal cited; relevant for journal articles. This is also the
|
||||
* system used at the Protein Data Bank (PDB).
|
||||
*/
|
||||
journal_id_CSD: str,
|
||||
/**
|
||||
* The International Standard Serial Number (ISSN) code assigned to
|
||||
* the journal cited; relevant for journal articles.
|
||||
*/
|
||||
journal_id_ISSN: str,
|
||||
/**
|
||||
* Volume number of the journal cited; relevant for journal
|
||||
* articles.
|
||||
*/
|
||||
journal_volume: str,
|
||||
/**
|
||||
* The first page of the citation; relevant for journal
|
||||
* articles, books and book chapters.
|
||||
*/
|
||||
page_first: str,
|
||||
/**
|
||||
* The last page of the citation; relevant for journal
|
||||
* articles, books and book chapters.
|
||||
*/
|
||||
page_last: str,
|
||||
/**
|
||||
* The title of the citation; relevant for journal articles, books
|
||||
* and book chapters.
|
||||
*/
|
||||
title: str,
|
||||
/**
|
||||
* The year of the citation; relevant for journal articles, books
|
||||
* and book chapters.
|
||||
*/
|
||||
year: int,
|
||||
/**
|
||||
* Document Object Identifier used by doi.org to uniquely
|
||||
* specify bibliographic entry.
|
||||
*/
|
||||
pdbx_database_id_DOI: str,
|
||||
/**
|
||||
* Ascession number used by PubMed to categorize a specific
|
||||
* bibliographic entry.
|
||||
*/
|
||||
pdbx_database_id_PubMed: int,
|
||||
},
|
||||
/**
|
||||
* Data items in the CITATION_AUTHOR category record details
|
||||
* about the authors associated with the citations in the
|
||||
* CITATION list.
|
||||
*/
|
||||
citation_author: {
|
||||
/**
|
||||
* This data item is a pointer to _citation.id in the CITATION
|
||||
* category.
|
||||
*/
|
||||
citation_id: str,
|
||||
/**
|
||||
* Name of an author of the citation; relevant for journal
|
||||
* articles, books and book chapters.
|
||||
*
|
||||
* The family name(s), followed by a comma and including any
|
||||
* dynastic components, precedes the first name(s) or initial(s).
|
||||
*/
|
||||
name: str,
|
||||
/**
|
||||
* This data item defines the order of the author's name in the
|
||||
* list of authors of a citation.
|
||||
*/
|
||||
ordinal: int,
|
||||
},
|
||||
/**
|
||||
* Data items in the DATABASE_2 category record details about the
|
||||
* database identifiers of the data block.
|
||||
*
|
||||
* These data items are assigned by database managers and should
|
||||
* only appear in a data block if they originate from that source.
|
||||
*
|
||||
* The name of this category, DATABASE_2, arose because the
|
||||
* category name DATABASE was already in use in the core CIF
|
||||
* dictionary, but was used differently from the way it needed
|
||||
* to be used in the mmCIF dictionary. Since CIF data names
|
||||
* cannot be changed once they have been adopted, a new category
|
||||
* had to be created.
|
||||
*/
|
||||
database_2: {
|
||||
/**
|
||||
* An abbreviation that identifies the database.
|
||||
*/
|
||||
database_id: Aliased<'CAS' | 'CSD' | 'EMDB' | 'ICSD' | 'MDF' | 'NDB' | 'NBS' | 'PDB' | 'PDF' | 'RCSB' | 'EBI' | 'PDBE' | 'BMRB' | 'WWPDB' | 'PDB_ACC'>(str),
|
||||
/**
|
||||
* The code assigned by the database identified in
|
||||
* _database_2.database_id.
|
||||
*/
|
||||
database_code: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the ENTITY category record details (such as
|
||||
* chemical composition, name and source) about the molecular
|
||||
@@ -741,6 +922,11 @@ export const mmCIF_Schema = {
|
||||
* and to distinguish this structural result from others.
|
||||
*/
|
||||
title: str,
|
||||
/**
|
||||
* An automatically generated descriptor for an NDB structure or
|
||||
* the unstructured content of the PDB COMPND record.
|
||||
*/
|
||||
pdbx_descriptor: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the STRUCT_ASYM category record details about the
|
||||
@@ -1680,6 +1866,20 @@ export const mmCIF_Schema = {
|
||||
*/
|
||||
content_type: Aliased<'minimized average structure' | 'representative structure' | 'ensemble' | 'derivative structure' | 'native structure' | 'associated EM volume' | 'other EM volume' | 'associated NMR restraints' | 'associated structure factors' | 'associated SAS data' | 'protein target sequence and/or protocol data' | 'split' | 're-refinement' | 'complete structure' | 'unspecified' | 'other'>(str),
|
||||
},
|
||||
pdbx_entity_nonpoly: {
|
||||
/**
|
||||
* This data item is a pointer to _entity.id in the ENTITY category.
|
||||
*/
|
||||
entity_id: str,
|
||||
/**
|
||||
* This data item is a pointer to _chem_comp.id in the CHEM_COMP category.
|
||||
*/
|
||||
comp_id: str,
|
||||
/**
|
||||
* A name for the non-polymer entity
|
||||
*/
|
||||
name: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the CHEM_COMP_IDENTIFIER category provide
|
||||
* identifiers for chemical components.
|
||||
@@ -2215,15 +2415,18 @@ export const mmCIF_Schema = {
|
||||
* This data item is a pointer to _entity.id in the ENTITY category.
|
||||
*/
|
||||
entity_id: str,
|
||||
/**
|
||||
* Scientific name of the organism of the natural source.
|
||||
*/
|
||||
pdbx_organism_scientific: str,
|
||||
/**
|
||||
* The plasmid containing the gene.
|
||||
*/
|
||||
pdbx_plasmid_name: str,
|
||||
/**
|
||||
* This data item is an ordinal identifier for entity_src_nat data records.
|
||||
*/
|
||||
pdbx_src_id: int,
|
||||
/**
|
||||
* This data item identifies cases in which an alternative source
|
||||
* modeled.
|
||||
*/
|
||||
pdbx_alt_source_flag: Aliased<'sample' | 'model'>(str),
|
||||
/**
|
||||
* The beginning polymer sequence position for the polymer section corresponding
|
||||
* to this source.
|
||||
@@ -2257,19 +2460,22 @@ export const mmCIF_Schema = {
|
||||
* Identifies the gene.
|
||||
*/
|
||||
pdbx_gene_src_gene: List(',', x => x),
|
||||
/**
|
||||
* Scientific name of the organism.
|
||||
*/
|
||||
pdbx_gene_src_scientific_name: str,
|
||||
/**
|
||||
* The name of the plasmid that produced the entity in the host
|
||||
* organism. Where full details of the protein production are available
|
||||
* it would be expected that this item would be derived from
|
||||
* _pdbx_construct.name of the construct pointed to from
|
||||
* _entity_src_gen_express.plasmid_id.
|
||||
*/
|
||||
plasmid_name: str,
|
||||
/**
|
||||
* This data item is an ordinal identifier for entity_src_gen data records.
|
||||
*/
|
||||
pdbx_src_id: int,
|
||||
/**
|
||||
* This data item identifies cases in which an alternative source
|
||||
* modeled.
|
||||
*/
|
||||
pdbx_alt_source_flag: Aliased<'sample' | 'model'>(str),
|
||||
/**
|
||||
* This data item povides additional information about the sequence type.
|
||||
*/
|
||||
pdbx_seq_type: Aliased<'N-terminal tag' | 'C-terminal tag' | 'Biological sequence' | 'Linker'>(str),
|
||||
/**
|
||||
* The beginning polymer sequence position for the polymer section corresponding
|
||||
* to this source.
|
||||
@@ -2290,6 +2496,11 @@ export const mmCIF_Schema = {
|
||||
* about chemically synthesized molecules.
|
||||
*/
|
||||
pdbx_entity_src_syn: {
|
||||
/**
|
||||
* The scientific name of the organism from which the sequence of
|
||||
* the synthetic entity was derived.
|
||||
*/
|
||||
organism_scientific: str,
|
||||
/**
|
||||
* This data item is a pointer to _entity.id in the ENTITY category.
|
||||
*/
|
||||
@@ -2298,11 +2509,6 @@ export const mmCIF_Schema = {
|
||||
* This data item is an ordinal identifier for pdbx_entity_src_syn data records.
|
||||
*/
|
||||
pdbx_src_id: int,
|
||||
/**
|
||||
* This data item identifies cases in which an alternative source
|
||||
* modeled.
|
||||
*/
|
||||
pdbx_alt_source_flag: Aliased<'sample' | 'model'>(str),
|
||||
/**
|
||||
* The beginning polymer sequence position for the polymer section corresponding
|
||||
* to this source.
|
||||
@@ -3050,7 +3256,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The type of data held in the dataset.
|
||||
*/
|
||||
data_type: Aliased<'NMR data' | '3DEM volume' | '2DEM class average' | 'EM raw micrographs' | 'SAS data' | 'CX-MS data' | 'Mass Spectrometry data' | 'EPR data' | 'H/D exchange data' | 'Single molecule FRET data' | 'Experimental model' | 'Comparative model' | 'Integrative model' | 'De Novo model' | 'Predicted contacts' | 'Mutagenesis data' | 'DNA footprinting data' | 'Hydroxyl radical footprinting data' | 'Yeast two-hybrid screening data' | 'Other'>(str),
|
||||
data_type: Aliased<'NMR data' | '3DEM volume' | '2DEM class average' | 'EM raw micrographs' | 'SAS data' | 'CX-MS data' | 'Mass Spectrometry data' | 'EPR data' | 'H/D exchange data' | 'Single molecule FRET data' | 'Experimental model' | 'Comparative model' | 'Integrative model' | 'De Novo model' | 'Predicted contacts' | 'Mutagenesis data' | 'DNA footprinting data' | 'Hydroxyl radical footprinting data' | 'Yeast two-hybrid screening data' | 'Quantitative measurements of genetic interactions' | 'Other'>(str),
|
||||
/**
|
||||
* A flag that indicates whether the dataset is archived in
|
||||
* an IHM related database or elsewhere.
|
||||
@@ -3225,7 +3431,7 @@ export const mmCIF_Schema = {
|
||||
*/
|
||||
file_size_bytes: float,
|
||||
/**
|
||||
* Textual description of what the external file is.
|
||||
* Additional textual details regarding the external file.
|
||||
*/
|
||||
details: str,
|
||||
},
|
||||
@@ -3459,7 +3665,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The type of crosslinker used.
|
||||
*/
|
||||
linker_type: Aliased<'EDC' | 'DSS' | 'EGS' | 'BS3' | 'BS2G' | 'DST' | 'sulfo-SDA' | 'sulfo-SMCC' | 'DSSO' | 'Other'>(str),
|
||||
linker_type: Aliased<'EDC' | 'DSS' | 'EGS' | 'BS3' | 'BS2G' | 'DST' | 'sulfo-SDA' | 'sulfo-SMCC' | 'DSSO' | 'DSG' | 'BSP' | 'Other'>(str),
|
||||
/**
|
||||
* Identifier to the crosslinking dataset.
|
||||
* This data item is a pointer to the _ihm_dataset_list.id in the
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* 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>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -23,7 +24,7 @@
|
||||
*/
|
||||
|
||||
import * as Data from '../data-model'
|
||||
import { Tokens, TokenBuilder } from '../../common/text/tokenizer'
|
||||
import { Tokens, TokenBuilder, Tokenizer } from '../../common/text/tokenizer'
|
||||
import { ReaderResult as Result } from '../../result'
|
||||
import { Task, RuntimeContext, chunkedSubtask } from '../../../../mol-task'
|
||||
|
||||
@@ -46,6 +47,8 @@ interface TokenizerState {
|
||||
position: number,
|
||||
length: number,
|
||||
isEscaped: boolean,
|
||||
isImportGet: boolean,
|
||||
inSaveFrame: boolean,
|
||||
|
||||
lineNumber: number,
|
||||
tokenType: CifTokenType,
|
||||
@@ -168,6 +171,23 @@ function eatMultiline(state: TokenizerState) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
function eatImportGet(state: TokenizerState) {
|
||||
// _import.get [{'save':orient_matrix 'file':templ_attr.cif}]
|
||||
// skipWhitespace(state)
|
||||
while (state.position < state.length) {
|
||||
switch (state.data.charCodeAt(state.position)) {
|
||||
case 93: // ]
|
||||
++state.position;
|
||||
state.tokenEnd = state.position;
|
||||
state.isImportGet = false
|
||||
return;
|
||||
default:
|
||||
++state.position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips until \n or \r occurs -- therefore the newlines get handled by the "skipWhitespace" function.
|
||||
*/
|
||||
@@ -274,6 +294,25 @@ function isLoop(state: TokenizerState): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
function isImportGet(state: TokenizerState): boolean {
|
||||
// _import.get [{'save':orient_matrix 'file':templ_attr.cif}]
|
||||
|
||||
if (state.tokenEnd - state.tokenStart !== 11) return false;
|
||||
|
||||
if (state.data.charCodeAt(state.tokenStart + 1) !== 105) return false; // i
|
||||
if (state.data.charCodeAt(state.tokenStart + 2) !== 109) return false; // m
|
||||
if (state.data.charCodeAt(state.tokenStart + 3) !== 112) return false; // p
|
||||
if (state.data.charCodeAt(state.tokenStart + 4) !== 111) return false; // o
|
||||
if (state.data.charCodeAt(state.tokenStart + 5) !== 114) return false; // r
|
||||
if (state.data.charCodeAt(state.tokenStart + 6) !== 116) return false; // t
|
||||
if (state.data.charCodeAt(state.tokenStart + 7) !== 46) return false; // .
|
||||
if (state.data.charCodeAt(state.tokenStart + 8) !== 103) return false; // g
|
||||
if (state.data.charCodeAt(state.tokenStart + 9) !== 101) return false; // e
|
||||
if (state.data.charCodeAt(state.tokenStart + 10) !== 116) return false; // t
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current token shares the namespace with string at <start,end).
|
||||
*/
|
||||
@@ -315,6 +354,17 @@ function getNamespace(state: TokenizerState, endIndex: number) {
|
||||
return state.data.substring(state.tokenStart, endIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current token contain no '.', otherwise returns false.
|
||||
*/
|
||||
function isFlatNamespace(state: TokenizerState): boolean {
|
||||
let i: number;
|
||||
for (i = state.tokenStart; i < state.tokenEnd; ++i) {
|
||||
if (state.data.charCodeAt(i) === 46) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation of the current token.
|
||||
*/
|
||||
@@ -336,6 +386,7 @@ function moveNextInternal(state: TokenizerState) {
|
||||
state.tokenStart = state.position;
|
||||
state.tokenEnd = state.position;
|
||||
state.isEscaped = false;
|
||||
|
||||
let c = state.data.charCodeAt(state.position);
|
||||
switch (c) {
|
||||
case 35: // #, comment
|
||||
@@ -357,20 +408,28 @@ function moveNextInternal(state: TokenizerState) {
|
||||
state.tokenType = CifTokenType.Value;
|
||||
break;
|
||||
default:
|
||||
eatValue(state);
|
||||
if (state.isImportGet) {
|
||||
eatImportGet(state);
|
||||
} else {
|
||||
eatValue(state);
|
||||
}
|
||||
|
||||
// escaped is always Value
|
||||
if (state.isEscaped) {
|
||||
state.tokenType = CifTokenType.Value;
|
||||
// _ always means column name
|
||||
// _ means column name, including _import.get
|
||||
} else if (state.data.charCodeAt(state.tokenStart) === 95) { // _
|
||||
if (state.inSaveFrame && isImportGet(state)) {
|
||||
state.isImportGet = true
|
||||
}
|
||||
state.tokenType = CifTokenType.ColumnName;
|
||||
// 5th char needs to be _ for data_ or loop_
|
||||
// 5th char needs to be _ for data_, save_ or loop_
|
||||
} else if (state.tokenEnd - state.tokenStart >= 5 && state.data.charCodeAt(state.tokenStart + 4) === 95) {
|
||||
if (isData(state)) state.tokenType = CifTokenType.Data;
|
||||
else if (isSave(state)) state.tokenType = CifTokenType.Save;
|
||||
else if (isLoop(state)) state.tokenType = CifTokenType.Loop;
|
||||
else state.tokenType = CifTokenType.Value;
|
||||
// all other tests failed, we are at Value token.
|
||||
// all other tests failed, we are at Value token.
|
||||
} else {
|
||||
state.tokenType = CifTokenType.Value;
|
||||
}
|
||||
@@ -396,6 +455,8 @@ function createTokenizer(data: string, runtimeCtx: RuntimeContext): TokenizerSta
|
||||
tokenType: CifTokenType.End,
|
||||
lineNumber: 1,
|
||||
isEscaped: false,
|
||||
isImportGet: false,
|
||||
inSaveFrame: false,
|
||||
|
||||
runtimeCtx
|
||||
};
|
||||
@@ -410,13 +471,48 @@ interface CifCategoryResult {
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
interface CifCategoryData {
|
||||
name: string,
|
||||
rowCount: number,
|
||||
fieldNames: string[],
|
||||
fields: { [name: string]: Data.CifField }
|
||||
}
|
||||
|
||||
type FrameContext = {
|
||||
categoryNames: string[],
|
||||
categories: { [name: string]: Data.CifCategory }
|
||||
categoryData: { [name: string]: CifCategoryData }
|
||||
}
|
||||
|
||||
function FrameContext(): FrameContext {
|
||||
return { categoryNames: [], categories: Object.create(null) };
|
||||
return { categoryNames: [], categoryData: Object.create(null) };
|
||||
}
|
||||
|
||||
function CifCategories(categoryNames: string[], categoryData: { [name: string]: CifCategoryData }): { [name: string]: Data.CifCategory } {
|
||||
const categories = Object.create(null)
|
||||
for (const name of categoryNames) {
|
||||
const d = categoryData[name]
|
||||
categories[name] = Data.CifCategory(d.name, d.rowCount, d.fieldNames, d.fields)
|
||||
}
|
||||
return categories
|
||||
}
|
||||
|
||||
function CifBlock(ctx: FrameContext, header: string, saveFrames?: Data.CifFrame[]): Data.CifBlock {
|
||||
return Data.CifBlock(ctx.categoryNames, CifCategories(ctx.categoryNames, ctx.categoryData), header, saveFrames)
|
||||
}
|
||||
|
||||
function CifSaveFrame(ctx: FrameContext, header: string): Data.CifBlock {
|
||||
return Data.CifBlock(ctx.categoryNames, CifCategories(ctx.categoryNames, ctx.categoryData), header)
|
||||
}
|
||||
|
||||
function addFields(ctx: FrameContext, name: string, rowCount: number, fieldNames: string[], fields: { [k: string]: Data.CifField }) {
|
||||
if (name in ctx.categoryData) {
|
||||
const cat = ctx.categoryData[name]
|
||||
cat.fieldNames.push(...fieldNames)
|
||||
Object.assign(cat.fields, fields)
|
||||
} else {
|
||||
ctx.categoryData[name] = { name, rowCount, fieldNames, fields };
|
||||
ctx.categoryNames.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,9 +545,7 @@ function handleSingle(tokenizer: TokenizerState, ctx: FrameContext): CifCategory
|
||||
moveNext(tokenizer);
|
||||
}
|
||||
|
||||
const catName = name.substr(1);
|
||||
ctx.categories[catName] = Data.CifCategory(catName, 1, fieldNames, fields);
|
||||
ctx.categoryNames.push(catName);
|
||||
addFields(ctx, name.substr(1), 1, fieldNames, fields)
|
||||
|
||||
return {
|
||||
hasError: false,
|
||||
@@ -496,10 +590,13 @@ async function handleLoop(tokenizer: TokenizerState, ctx: FrameContext): Promise
|
||||
|
||||
moveNext(tokenizer);
|
||||
const name = getNamespace(tokenizer, getNamespaceEnd(tokenizer));
|
||||
const isFlat = isFlatNamespace(tokenizer);
|
||||
const fieldNames: string[] = [];
|
||||
|
||||
while (tokenizer.tokenType === CifTokenType.ColumnName) {
|
||||
fieldNames[fieldNames.length] = getTokenString(tokenizer).substring(name.length + 1);
|
||||
fieldNames[fieldNames.length] = isFlat
|
||||
? getTokenString(tokenizer)
|
||||
: getTokenString(tokenizer).substring(name.length + 1);
|
||||
moveNext(tokenizer);
|
||||
}
|
||||
|
||||
@@ -526,14 +623,19 @@ async function handleLoop(tokenizer: TokenizerState, ctx: FrameContext): Promise
|
||||
}
|
||||
|
||||
const rowCount = (state.tokenCount / fieldCount) | 0;
|
||||
const fields = Object.create(null);
|
||||
for (let i = 0; i < fieldCount; i++) {
|
||||
fields[fieldNames[i]] = Data.CifField.ofTokens(tokens[i]);
|
||||
}
|
||||
if (isFlat) {
|
||||
for (let i = 0; i < fieldCount; i++) {
|
||||
const fields = { '': Data.CifField.ofTokens(tokens[i]) };
|
||||
addFields(ctx, fieldNames[i].substr(1), rowCount, [''], fields)
|
||||
}
|
||||
} else {
|
||||
const fields = Object.create(null);
|
||||
for (let i = 0; i < fieldCount; i++) {
|
||||
fields[fieldNames[i]] = Data.CifField.ofTokens(tokens[i]);
|
||||
}
|
||||
|
||||
const catName = name.substr(1);
|
||||
ctx.categories[catName] = Data.CifCategory(catName, rowCount, fieldNames, fields);
|
||||
ctx.categoryNames.push(catName);
|
||||
addFields(ctx, name.substr(1), rowCount, fieldNames, fields)
|
||||
}
|
||||
|
||||
return {
|
||||
hasError: false,
|
||||
@@ -568,12 +670,14 @@ async function parseInternal(data: string, runtimeCtx: RuntimeContext) {
|
||||
|
||||
let blockCtx = FrameContext();
|
||||
|
||||
let inSaveFrame = false;
|
||||
|
||||
// the next three initial values are never used in valid files
|
||||
let saveFrames: Data.CifFrame[] = [];
|
||||
let saveCtx = FrameContext();
|
||||
let saveFrame: Data.CifFrame = Data.CifSafeFrame(saveCtx.categoryNames, saveCtx.categories, '');
|
||||
let saveFrame: Data.CifFrame = Data.CifSaveFrame(
|
||||
saveCtx.categoryNames, CifCategories(saveCtx.categoryNames, saveCtx.categoryData), ''
|
||||
);
|
||||
|
||||
let saveHeader = ''
|
||||
|
||||
runtimeCtx.update({ message: 'Parsing...', current: 0, max: data.length });
|
||||
|
||||
@@ -583,11 +687,11 @@ async function parseInternal(data: string, runtimeCtx: RuntimeContext) {
|
||||
|
||||
// Data block
|
||||
if (token === CifTokenType.Data) {
|
||||
if (inSaveFrame) {
|
||||
if (tokenizer.inSaveFrame) {
|
||||
return error(tokenizer.lineNumber, 'Unexpected data block inside a save frame.');
|
||||
}
|
||||
if (blockCtx.categoryNames.length > 0) {
|
||||
dataBlocks.push(Data.CifBlock(blockCtx.categoryNames, blockCtx.categories, blockHeader, saveFrames));
|
||||
dataBlocks.push(CifBlock(blockCtx, blockHeader, saveFrames));
|
||||
}
|
||||
blockHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
|
||||
blockCtx = FrameContext();
|
||||
@@ -595,47 +699,47 @@ async function parseInternal(data: string, runtimeCtx: RuntimeContext) {
|
||||
moveNext(tokenizer);
|
||||
// Save frame
|
||||
} else if (token === CifTokenType.Save) {
|
||||
const saveHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
|
||||
if (saveHeader.length === 0) {
|
||||
if (tokenizer.tokenEnd - tokenizer.tokenStart === 5) { // end of save frame
|
||||
if (saveCtx.categoryNames.length > 0) {
|
||||
saveFrames[saveFrames.length] = saveFrame;
|
||||
saveFrames[saveFrames.length] = CifSaveFrame(saveCtx, saveHeader);
|
||||
}
|
||||
inSaveFrame = false;
|
||||
} else {
|
||||
if (inSaveFrame) {
|
||||
tokenizer.inSaveFrame = false;
|
||||
} else { // start of save frame
|
||||
if (tokenizer.inSaveFrame) {
|
||||
return error(tokenizer.lineNumber, 'Save frames cannot be nested.');
|
||||
}
|
||||
inSaveFrame = true;
|
||||
const safeHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
|
||||
tokenizer.inSaveFrame = true;
|
||||
saveHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
|
||||
saveCtx = FrameContext();
|
||||
saveFrame = Data.CifSafeFrame(saveCtx.categoryNames, saveCtx.categories, safeHeader);
|
||||
// saveFrame = CifSaveFrame(saveCtx, saveHeader);
|
||||
}
|
||||
moveNext(tokenizer);
|
||||
// Loop
|
||||
} else if (token === CifTokenType.Loop) {
|
||||
const cat = await handleLoop(tokenizer, inSaveFrame ? saveCtx : blockCtx);
|
||||
const cat = await handleLoop(tokenizer, tokenizer.inSaveFrame ? saveCtx : blockCtx);
|
||||
if (cat.hasError) {
|
||||
return error(cat.errorLine, cat.errorMessage);
|
||||
}
|
||||
// Single row
|
||||
} else if (token === CifTokenType.ColumnName) {
|
||||
const cat = handleSingle(tokenizer, inSaveFrame ? saveCtx : blockCtx);
|
||||
const cat = handleSingle(tokenizer, tokenizer.inSaveFrame ? saveCtx : blockCtx);
|
||||
if (cat.hasError) {
|
||||
return error(cat.errorLine, cat.errorMessage);
|
||||
}
|
||||
// Out of options
|
||||
} else {
|
||||
console.log(tokenizer.tokenType, Tokenizer.getTokenString(tokenizer))
|
||||
return error(tokenizer.lineNumber, 'Unexpected token. Expected data_, loop_, or data name.');
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the latest save frame was closed.
|
||||
if (inSaveFrame) {
|
||||
if (tokenizer.inSaveFrame) {
|
||||
return error(tokenizer.lineNumber, `Unfinished save frame (${saveFrame.header}).`);
|
||||
}
|
||||
|
||||
if (blockCtx.categoryNames.length > 0 || saveFrames.length > 0) {
|
||||
dataBlocks.push(Data.CifBlock(blockCtx.categoryNames, blockCtx.categories, blockHeader, saveFrames));
|
||||
dataBlocks.push(CifBlock(blockCtx, blockHeader, saveFrames));
|
||||
}
|
||||
|
||||
return result(Data.CifFile(dataBlocks));
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
*/
|
||||
|
||||
import { Vec3, Mat4 } from '../../linear-algebra'
|
||||
import { SpacegroupName, TransformData, GroupData, getSpacegroupIndex, OperatorData, SpacegroupNames } from './tables'
|
||||
import { SpacegroupName, TransformData, GroupData, getSpacegroupIndex, OperatorData, SpacegroupNumber } from './tables'
|
||||
import { SymmetryOperator } from '../../geometry';
|
||||
|
||||
interface SpacegroupCell {
|
||||
/** Zero based spacegroup number */
|
||||
/** Index into spacegroup data table */
|
||||
readonly index: number,
|
||||
readonly size: Vec3,
|
||||
readonly volume: number,
|
||||
@@ -22,7 +22,10 @@ interface SpacegroupCell {
|
||||
}
|
||||
|
||||
interface Spacegroup {
|
||||
/** Hermann-Mauguin spacegroup name */
|
||||
readonly name: string,
|
||||
/** Spacegroup number from International Tables for Crystallography */
|
||||
readonly num: number,
|
||||
readonly cell: SpacegroupCell,
|
||||
readonly operators: ReadonlyArray<Mat4>
|
||||
}
|
||||
@@ -72,14 +75,15 @@ namespace SpacegroupCell {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace Spacegroup {
|
||||
/** P1 with [1, 1, 1] cell */
|
||||
export const ZeroP1 = create(SpacegroupCell.Zero);
|
||||
|
||||
export function create(cell: SpacegroupCell): Spacegroup {
|
||||
const operators = GroupData[cell.index].map(i => getOperatorMatrix(OperatorData[i]));
|
||||
return { name: SpacegroupNames[cell.index], cell, operators };
|
||||
const name = SpacegroupName[cell.index]
|
||||
const num = SpacegroupNumber[cell.index]
|
||||
return { name, num, cell, operators };
|
||||
}
|
||||
|
||||
const _ijkVec = Vec3();
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-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>
|
||||
*/
|
||||
|
||||
export const TransformData = [
|
||||
@@ -31,26 +32,26 @@ export const TransformData = [
|
||||
[0.0, 0.0, -1.0, 0.75],
|
||||
[1.0, -1.0, 0.0, 0.0],
|
||||
[-1.0, 1.0, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0, 0.333333333333333],
|
||||
[0.0, 0.0, 1.0, 0.666666666666667],
|
||||
[1.0, 0.0, 0.0, 0.666666666666667],
|
||||
[0.0, 1.0, 0.0, 0.333333333333333],
|
||||
[0.0, -1.0, 0.0, 0.666666666666667],
|
||||
[1.0, -1.0, 0.0, 0.333333333333333],
|
||||
[-1.0, 1.0, 0.0, 0.666666666666667],
|
||||
[-1.0, 0.0, 0.0, 0.333333333333333],
|
||||
[1.0, 0.0, 0.0, 0.333333333333333],
|
||||
[0.0, 1.0, 0.0, 0.666666666666667],
|
||||
[0.0, -1.0, 0.0, 0.333333333333333],
|
||||
[1.0, -1.0, 0.0, 0.666666666666667],
|
||||
[-1.0, 1.0, 0.0, 0.333333333333333],
|
||||
[-1.0, 0.0, 0.0, 0.666666666666667],
|
||||
[0.0, 0.0, -1.0, 0.333333333333333],
|
||||
[0.0, 0.0, -1.0, 0.666666666666667],
|
||||
[0.0, 0.0, 1.0, 0.833333333333333],
|
||||
[0.0, 0.0, 1.0, 0.166666666666667],
|
||||
[0.0, 0.0, -1.0, 0.833333333333333],
|
||||
[0.0, 0.0, -1.0, 0.166666666666667],
|
||||
[0.0, 0.0, 1.0, 1/3],
|
||||
[0.0, 0.0, 1.0, 2/3],
|
||||
[1.0, 0.0, 0.0, 2/3],
|
||||
[0.0, 1.0, 0.0, 1/3],
|
||||
[0.0, -1.0, 0.0, 2/3],
|
||||
[1.0, -1.0, 0.0, 1/3],
|
||||
[-1.0, 1.0, 0.0, 2/3],
|
||||
[-1.0, 0.0, 0.0, 1/3],
|
||||
[1.0, 0.0, 0.0, 1/3],
|
||||
[0.0, 1.0, 0.0, 2/3],
|
||||
[0.0, -1.0, 0.0, 1/3],
|
||||
[1.0, -1.0, 0.0, 2/3],
|
||||
[-1.0, 1.0, 0.0, 1/3],
|
||||
[-1.0, 0.0, 0.0, 2/3],
|
||||
[0.0, 0.0, -1.0, 1/3],
|
||||
[0.0, 0.0, -1.0, 2/3],
|
||||
[0.0, 0.0, 1.0, 5/6],
|
||||
[0.0, 0.0, 1.0, 1/6],
|
||||
[0.0, 0.0, -1.0, 5/6],
|
||||
[0.0, 0.0, -1.0, 1/6],
|
||||
];
|
||||
|
||||
export const OperatorData = [
|
||||
@@ -970,6 +971,16 @@ export const GroupData = [
|
||||
[0, 52, 16, 1, 26, 59, 20, 65],
|
||||
[0, 31, 1, 63],
|
||||
[0, 1, 24, 62],
|
||||
[0, 15, 1, 9], // 'P 1 21/n 1'
|
||||
// X,Y,Z
|
||||
// -X+1/2,Y+1/2,-Z+1/2
|
||||
// -X,-Y,-Z
|
||||
// X+1/2,-Y+1/2,Z+1/2
|
||||
[0, 5, 1, 8], // 'P 1 21/a 1'
|
||||
// X,Y,Z
|
||||
// -X+1/2,Y+1/2,-Z
|
||||
// -X,-Y,-Z
|
||||
// X+1/2,-Y+1/2,Z
|
||||
[0, 31, 1, 63, 26, 21, 65, 54],
|
||||
[0, 2, 57, 56],
|
||||
[0, 60, 3, 16],
|
||||
@@ -985,7 +996,7 @@ export const GroupData = [
|
||||
[0, 22, 57, 3, 159, 279, 654, 655, 158, 274, 656, 657, 29, 18, 25, 27, 284, 658, 262, 269, 280, 659, 257, 267],
|
||||
];
|
||||
|
||||
export const ZeroBasedSpacegroupNumbers = {
|
||||
export const SpacegroupNameToIndexMap = {
|
||||
'P 1': 0,
|
||||
'P -1': 1,
|
||||
'P 1 2 1': 2,
|
||||
@@ -1318,44 +1329,164 @@ export const ZeroBasedSpacegroupNumbers = {
|
||||
'B 1 1 2/m': 250,
|
||||
'P 1 1 2/b': 251,
|
||||
'P 1 1 21/b': 252,
|
||||
'B 1 1 2/b': 253,
|
||||
'P 21 2 2': 254,
|
||||
'P 2 21 2': 255,
|
||||
'P 21 21 2 (a)': 256,
|
||||
'P 21 2 21': 257,
|
||||
'P 2 21 21': 258,
|
||||
'C 2 2 21a)': 259,
|
||||
'C 2 2 2a': 260,
|
||||
'F 2 2 2a': 261,
|
||||
'I 2 2 2a': 262,
|
||||
'P 21/m 21/m 2/n a': 263,
|
||||
'P 42 21 2a': 264,
|
||||
'I 2 3a': 265,
|
||||
'P 1 21/n 1': 253,
|
||||
'P 1 21/a 1': 254,
|
||||
'B 1 1 2/b': 255,
|
||||
'P 21 2 2': 256,
|
||||
'P 2 21 2': 257,
|
||||
'P 21 21 2 (a)': 258,
|
||||
'P 21 2 21': 259,
|
||||
'P 2 21 21': 260,
|
||||
'C 2 2 21a)': 261,
|
||||
'C 2 2 2a': 262,
|
||||
'F 2 2 2a': 263,
|
||||
'I 2 2 2a': 264,
|
||||
'P 21/m 21/m 2/n a': 265,
|
||||
'P 42 21 2a': 266,
|
||||
'I 2 3a': 267,
|
||||
};
|
||||
|
||||
export type SpacegroupName = keyof typeof ZeroBasedSpacegroupNumbers
|
||||
export function getSpacegroupIndexFromNumber(num: number) {
|
||||
// 38 spacegroup variants as given CCP4s symop.lib
|
||||
switch (num) {
|
||||
case 1146: return 146
|
||||
case 1148: return 149
|
||||
case 1155: return 157
|
||||
case 1160: return 163
|
||||
case 1161: return 165
|
||||
case 1166: return 171
|
||||
case 1167: return 173
|
||||
|
||||
export const SpacegroupNames: { [num: number]: SpacegroupName } = (function () {
|
||||
case 1003: return 237 // 'P 1 1 2' !(dyad along z)
|
||||
case 1004: return 238 // 'P 1 1 21' !(unique axis c)
|
||||
case 1005: return 239 // 'B 1 1 2' 'B 2'
|
||||
case 2005: return 240 // 'A 1 2 1'
|
||||
case 3005: return 241 // 'C 1 21 1' ! (Origin on screw at 1/4X)
|
||||
case 4005: return 242 // 'I 1 2 1' 'I 2' !!! GJK @ 2003-06-02
|
||||
case 5005: return 243 // 'I 1 21 1'
|
||||
case 1006: return 244 // 'P 1 1 m'
|
||||
case 1007: return 245 // 'P 1 1 b'
|
||||
case 1008: return 246 // 'B 1 1 m'
|
||||
case 1009: return 247 // 'B 1 1 b'
|
||||
case 1010: return 248 // 'P 1 1 2/m'
|
||||
case 1011: return 249 // 'P 1 1 21/m'
|
||||
case 1012: return 250 // 'B 1 1 2/m'
|
||||
case 1013: return 251 // 'P 1 1 2/b'
|
||||
case 1014: return 252 // 'P 1 1 21/b'
|
||||
case 2014: return 253 // 'P 1 21/n 1'
|
||||
case 3014: return 254 // 'P 1 21/a 1'
|
||||
case 1015: return 255 // 'B 1 1 2/b'
|
||||
case 1017: return 256 // 'P 21 2 2' !(unique axis a)
|
||||
case 2017: return 257 // 'P 2 21 2' !(unique axis b)
|
||||
case 1018: return 258 // 'P 21 21 2 (a)' ! origin on 21 21, shift (1/4,1/4,0)
|
||||
case 2018: return 259 // 'P 21 2 21' !(unique axis b)
|
||||
case 3018: return 260 // 'P 2 21 21' !(unique axis a)
|
||||
case 1020: return 261 // 'C 2 2 21a)' ! P212121 with C centring, shift(1/4,0,0)
|
||||
case 1021: return 262 // 'C 2 2 2a' ! C21212a origin on 21 21
|
||||
case 1022: return 263 // 'F 2 2 2a' ! same as 1018 with face centring shift (1/4,0,0)
|
||||
case 1023: return 264 // 'I 2 2 2a' ! as 1018 with origin shift (1/4,1/4,1/4)
|
||||
case 1059: return 265 // 'P 21/m 21/m 2/n a'
|
||||
case 1094: return 266 // 'P 42 21 2a' ! (as P21212a) origin on 21 21 ie Shift 1/4,1/4,1/4
|
||||
case 1197: return 267 // 'I 2 3a' ! Expansion of 1023 which is an expansion of 1018
|
||||
}
|
||||
|
||||
let offset = 0
|
||||
if (num > 146) ++offset
|
||||
if (num > 148) ++offset
|
||||
if (num > 155) ++offset
|
||||
if (num > 160) ++offset
|
||||
if (num > 161) ++offset
|
||||
if (num > 166) ++offset
|
||||
if (num > 167) ++offset
|
||||
|
||||
return num - 1 + offset
|
||||
}
|
||||
|
||||
export function getSpacegroupNumberFromIndex(idx: number) {
|
||||
if (idx < 146) return idx + 1
|
||||
if (idx === 146) return 1146
|
||||
|
||||
if (idx < 149) return idx + 1 - 1
|
||||
if (idx === 149) return 1148
|
||||
|
||||
if (idx < 157) return idx + 1 - 2
|
||||
if (idx === 157) return 1155
|
||||
|
||||
if (idx < 163) return idx + 1 - 3
|
||||
if (idx === 163) return 1160
|
||||
|
||||
if (idx < 165) return idx + 1 - 4
|
||||
if (idx === 165) return 1161
|
||||
|
||||
if (idx < 171) return idx + 1 - 5
|
||||
if (idx === 171) return 1166
|
||||
|
||||
if (idx < 173) return idx + 1 - 6
|
||||
if (idx === 173) return 1167
|
||||
|
||||
if (idx < 237) return idx + 1 - 7
|
||||
if (idx === 237) return 1003
|
||||
if (idx === 238) return 1004
|
||||
if (idx === 239) return 1005
|
||||
if (idx === 240) return 2005
|
||||
if (idx === 241) return 3005
|
||||
if (idx === 242) return 4005
|
||||
if (idx === 243) return 5005
|
||||
if (idx === 244) return 1006
|
||||
if (idx === 245) return 1007
|
||||
if (idx === 246) return 1008
|
||||
if (idx === 247) return 1009
|
||||
if (idx === 248) return 1010
|
||||
if (idx === 249) return 1011
|
||||
if (idx === 250) return 1012
|
||||
if (idx === 251) return 1013
|
||||
if (idx === 252) return 1014
|
||||
|
||||
if (idx === 253) return 2014
|
||||
if (idx === 254) return 3014
|
||||
if (idx === 255) return 1015
|
||||
if (idx === 256) return 1017
|
||||
if (idx === 257) return 2017
|
||||
if (idx === 258) return 1018
|
||||
if (idx === 259) return 2018
|
||||
if (idx === 260) return 3018
|
||||
if (idx === 261) return 1020
|
||||
if (idx === 262) return 1021
|
||||
if (idx === 263) return 1022
|
||||
if (idx === 264) return 1023
|
||||
if (idx === 265) return 1059
|
||||
if (idx === 266) return 1094
|
||||
if (idx === 267) return 1197
|
||||
|
||||
throw new Error(`unknown spacegroup index '${idx}'`)
|
||||
}
|
||||
|
||||
export type SpacegroupName = keyof typeof SpacegroupNameToIndexMap
|
||||
|
||||
/** Maps spacegroup index to Hermann-Mauguin spacegroup name */
|
||||
export const SpacegroupName: { [idx: number]: SpacegroupName } = (function () {
|
||||
const names = Object.create(null);
|
||||
for (const n of Object.keys(ZeroBasedSpacegroupNumbers)) {
|
||||
names[(ZeroBasedSpacegroupNumbers as any)[n]] = n;
|
||||
for (const n of Object.keys(SpacegroupNameToIndexMap)) {
|
||||
names[(SpacegroupNameToIndexMap as any)[n]] = n;
|
||||
}
|
||||
return names;
|
||||
}());
|
||||
|
||||
// return -1 if the spacegroup does not exist.
|
||||
export function getSpacegroupIndex(nameOrNumber: number | string | SpacegroupName): number {
|
||||
let index: number
|
||||
if (typeof nameOrNumber === 'number') {
|
||||
// used by CCP4, see http://www.ccp4.ac.uk/html/pointless.html#setting
|
||||
if (nameOrNumber === 1017) index = 254
|
||||
else if (nameOrNumber === 2017) index = 255
|
||||
else if (nameOrNumber === 2018) index = 257
|
||||
else if (nameOrNumber === 3018) index = 258
|
||||
else index = nameOrNumber - 1
|
||||
} else {
|
||||
index = ZeroBasedSpacegroupNumbers[nameOrNumber as SpacegroupName];
|
||||
/** Maps spacegroup index to spacegroup number from International Tables for Crystallography */
|
||||
export const SpacegroupNumber: { [idx: number]: number } = (function () {
|
||||
const numbers = Object.create(null);
|
||||
for (const n of Object.keys(SpacegroupNameToIndexMap)) {
|
||||
const idx = (SpacegroupNameToIndexMap as any)[n]
|
||||
numbers[idx] = getSpacegroupNumberFromIndex(idx);
|
||||
}
|
||||
if (typeof index === 'undefined' || typeof SpacegroupNames[index] === 'undefined') return -1;
|
||||
return numbers;
|
||||
}());
|
||||
|
||||
/** return -1 if the spacegroup does not exist */
|
||||
export function getSpacegroupIndex(nameOrNumber: number | string | SpacegroupName): number {
|
||||
const index = typeof nameOrNumber === 'number'
|
||||
? getSpacegroupIndexFromNumber(nameOrNumber)
|
||||
: SpacegroupNameToIndexMap[nameOrNumber as SpacegroupName];
|
||||
if (typeof index === 'undefined' || typeof SpacegroupName[index] === 'undefined') return -1;
|
||||
return index;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* 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>
|
||||
@@ -25,4 +25,10 @@ import Vec4 from './3d/vec4'
|
||||
import Quat from './3d/quat'
|
||||
import { EPSILON } from './3d/common'
|
||||
|
||||
export { Mat4, Mat3, Vec2, Vec3, Vec4, Quat, EPSILON }
|
||||
export { Mat4, Mat3, Vec2, Vec3, Vec4, Quat, EPSILON }
|
||||
|
||||
export type Vec<T> =
|
||||
T extends 4 ? Vec4 :
|
||||
T extends 3 ? Vec3 :
|
||||
T extends 2 ? Vec2 :
|
||||
number[]
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* 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>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* 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>
|
||||
@@ -23,6 +23,7 @@ import { spline as _spline, quadraticBezier as _quadraticBezier, clamp } from '.
|
||||
import { NumberArray } from '../../../mol-util/type-helpers';
|
||||
|
||||
interface Vec3 extends Array<number> { [d: number]: number, '@type': 'vec3', length: 3 }
|
||||
interface ReadonlyVec3 extends Array<number> { readonly [d: number]: number, '@type': 'vec3', length: 3 }
|
||||
|
||||
function Vec3() {
|
||||
return Vec3.zero();
|
||||
@@ -497,13 +498,12 @@ namespace Vec3 {
|
||||
}
|
||||
|
||||
const rotTemp = zero();
|
||||
const flipScaling = create(-1, -1, -1);
|
||||
export function makeRotation(mat: Mat4, a: Vec3, b: Vec3): Mat4 {
|
||||
const by = angle(a, b);
|
||||
if (Math.abs(by) < 0.0001) return Mat4.setIdentity(mat);
|
||||
if (Math.abs(by - Math.PI) < EPSILON) {
|
||||
// here, axis can be [0,0,0] but the rotation is a simple flip
|
||||
return Mat4.fromScaling(mat, flipScaling);
|
||||
return Mat4.fromScaling(mat, negUnit);
|
||||
}
|
||||
const axis = cross(rotTemp, a, b);
|
||||
return Mat4.fromRotation(mat, by, axis);
|
||||
@@ -525,6 +525,16 @@ namespace Vec3 {
|
||||
return normalize(out, cross(out, cross(out, a, b), a));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a vector like `a` that point into the same general direction as `b`,
|
||||
* i.e. where the dot product is > 0
|
||||
*/
|
||||
export function matchDirection(out: Vec3, a: Vec3, b: Vec3) {
|
||||
if (Vec3.dot(a, b) > 0) Vec3.copy(out, a)
|
||||
else Vec3.negate(out, Vec3.copy(out, a))
|
||||
return out
|
||||
}
|
||||
|
||||
const triangleNormalTmpAB = zero();
|
||||
const triangleNormalTmpAC = zero();
|
||||
/** Calculate normal for the triangle defined by `a`, `b` and `c` */
|
||||
@@ -537,6 +547,9 @@ namespace Vec3 {
|
||||
export function toString(a: Vec3, precision?: number) {
|
||||
return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)}]`;
|
||||
}
|
||||
|
||||
export const unit: ReadonlyVec3 = Vec3.create(1, 1, 1)
|
||||
export const negUnit: ReadonlyVec3 = Vec3.create(-1, -1, -1)
|
||||
}
|
||||
|
||||
export default Vec3
|
||||
@@ -1,47 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { NumberArray } from '../../../mol-util/type-helpers';
|
||||
import { Vec } from '../3d';
|
||||
|
||||
interface Matrix { data: NumberArray, size: number, cols: number, rows: number }
|
||||
interface Matrix<N extends number = number, M extends number = number> {
|
||||
data: NumberArray,
|
||||
size: number,
|
||||
cols: N,
|
||||
rows: M
|
||||
}
|
||||
|
||||
namespace Matrix {
|
||||
export function create(cols: number, rows: number, ctor: { new (size: number): NumberArray } = Float32Array): Matrix {
|
||||
export function create<N extends number, M extends number>(cols: N, rows: M, ctor: { new (size: number): NumberArray } = Float32Array): Matrix<N, M> {
|
||||
const size = cols * rows
|
||||
return { data: new ctor(size), size, cols, rows }
|
||||
}
|
||||
|
||||
/** Get element assuming data are stored in column-major order */
|
||||
export function get(m: Matrix, i: number, j: number) { return m.data[m.rows * j + i]; }
|
||||
/** Set element assuming data are stored in column-major order */
|
||||
export function set(m: Matrix, i: number, j: number, value: number) { m.data[m.rows * j + i] = value; }
|
||||
/** Add to element assuming data are stored in column-major order */
|
||||
export function add(m: Matrix, i: number, j: number, value: number) { m.data[m.rows * j + i] += value; }
|
||||
/** Zero out the matrix */
|
||||
export function makeZero(m: Matrix) {
|
||||
for (let i = 0, _l = m.data.length; i < _l; i++) m.data[i] = 0.0;
|
||||
export function get(m: Matrix, i: number, j: number) {
|
||||
return m.data[m.rows * j + i];
|
||||
}
|
||||
|
||||
export function fromArray(data: NumberArray, cols: number, rows: number): Matrix {
|
||||
/** Set element assuming data are stored in column-major order */
|
||||
export function set<N extends number, M extends number>(m: Matrix<N, M>, i: number, j: number, value: number) {
|
||||
m.data[m.rows * j + i] = value;
|
||||
return m
|
||||
}
|
||||
|
||||
/** Add to element assuming data are stored in column-major order */
|
||||
export function add<N extends number, M extends number>(m: Matrix<N, M>, i: number, j: number, value: number) {
|
||||
m.data[m.rows * j + i] += value;
|
||||
return m
|
||||
}
|
||||
|
||||
/** Zero out the matrix */
|
||||
export function makeZero<N extends number, M extends number>(m: Matrix<N, M>) {
|
||||
m.data.fill(0.0)
|
||||
return m
|
||||
}
|
||||
|
||||
export function clone<N extends number, M extends number>(m: Matrix<N, M>): Matrix<N, M> {
|
||||
return { data: m.data.slice(), size: m.size, cols: m.cols, rows: m.rows }
|
||||
}
|
||||
|
||||
export function fromArray<N extends number, M extends number>(data: NumberArray, cols: N, rows: M): Matrix<N, M> {
|
||||
return { data, size: cols * rows, cols, rows }
|
||||
}
|
||||
|
||||
export function transpose(out: Matrix, mat: Matrix): Matrix {
|
||||
export function transpose<N extends number, M extends number>(out: Matrix<M, N>, mat: Matrix<N, M>): Matrix<M, N> {
|
||||
if (out.cols !== mat.rows || out.rows !== mat.cols) {
|
||||
throw new Error('transpose: matrix dimensions incompatible')
|
||||
}
|
||||
if (out.data === mat.data) {
|
||||
throw new Error('transpose: matrices share memory')
|
||||
}
|
||||
const nrows = mat.rows, ncols = mat.cols
|
||||
const md = mat.data, mtd = out.data
|
||||
|
||||
for (let i = 0, mi = 0, mti = 0; i < nrows; mti += 1, mi += ncols, ++i) {
|
||||
let ri = mti
|
||||
for (let j = 0; j < ncols; ri += nrows, j++) mtd[ri] = md[mi + j]
|
||||
}
|
||||
return mat
|
||||
return out
|
||||
}
|
||||
|
||||
/** out = matA * matB' */
|
||||
export function multiplyABt (out: Matrix, matA: Matrix, matB: Matrix) {
|
||||
export function multiplyABt<NA extends number, NB extends number, M extends number>(out: Matrix<M, M>, matA: Matrix<NA, M>, matB: Matrix<NB, M>): Matrix<M, M> {
|
||||
const ncols = matA.cols, nrows = matA.rows, mrows = matB.rows
|
||||
const ad = matA.data, bd = matB.data, cd = out.data
|
||||
|
||||
@@ -59,10 +86,10 @@ namespace Matrix {
|
||||
}
|
||||
|
||||
/** Get the mean of rows in `mat` */
|
||||
export function meanRows (mat: Matrix) {
|
||||
export function meanRows<N extends number, M extends number, V extends Vec<N>>(mat: Matrix<N, M>): V {
|
||||
const nrows = mat.rows, ncols = mat.cols
|
||||
const md = mat.data
|
||||
const mean = new Array(ncols)
|
||||
const mean = new Array(ncols) as V
|
||||
|
||||
for (let j = 0; j < ncols; ++j) mean[ j ] = 0.0
|
||||
for (let i = 0, p = 0; i < nrows; ++i) {
|
||||
@@ -74,7 +101,7 @@ namespace Matrix {
|
||||
}
|
||||
|
||||
/** Subtract `row` from all rows in `mat` */
|
||||
export function subRows (mat: Matrix, row: NumberArray) {
|
||||
export function subRows<N extends number, M extends number>(mat: Matrix<N, M>, row: NumberArray) {
|
||||
const nrows = mat.rows, ncols = mat.cols
|
||||
const md = mat.data
|
||||
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import Matrix from './matrix';
|
||||
import { Vec3 } from '../3d';
|
||||
// import { Vec3, Mat4 } from '../3d.js';
|
||||
import { Vec3, Mat4 } from '../3d';
|
||||
import { svd } from './svd';
|
||||
import { NumberArray } from '../../../mol-util/type-helpers';
|
||||
|
||||
// const negateVector = Vec3.create(-1, -1, -1)
|
||||
// const tmpMatrix = Mat4.identity()
|
||||
export { PrincipalAxes }
|
||||
|
||||
/**
|
||||
* Principal axes
|
||||
*/
|
||||
class PrincipalAxes {
|
||||
interface PrincipalAxes {
|
||||
begA: Vec3
|
||||
endA: Vec3
|
||||
begB: Vec3
|
||||
@@ -32,14 +28,15 @@ class PrincipalAxes {
|
||||
normVecA: Vec3
|
||||
normVecB: Vec3
|
||||
normVecC: Vec3
|
||||
}
|
||||
|
||||
namespace PrincipalAxes {
|
||||
/**
|
||||
* points is a 3xN matrix
|
||||
* @param points 3xN matrix
|
||||
*/
|
||||
constructor(points: Matrix) {
|
||||
export function ofPoints(points: Matrix<3, number>): PrincipalAxes {
|
||||
const n = points.rows
|
||||
const n3 = n / 3
|
||||
const pointsT = Matrix.create(n, 3)
|
||||
const A = Matrix.create(3, 3)
|
||||
const W = Matrix.create(1, 3)
|
||||
const U = Matrix.create(3, 3)
|
||||
@@ -47,145 +44,102 @@ class PrincipalAxes {
|
||||
|
||||
// calculate
|
||||
const mean = Matrix.meanRows(points)
|
||||
Matrix.subRows(points, mean)
|
||||
Matrix.transpose(pointsT, points)
|
||||
const pointsM = Matrix.subRows(Matrix.clone(points), mean)
|
||||
const pointsT = Matrix.transpose(Matrix.create(n, 3), pointsM)
|
||||
Matrix.multiplyABt(A, pointsT, pointsT)
|
||||
svd(A, W, U, V)
|
||||
|
||||
// center
|
||||
const vm = Vec3.create(mean[0], mean[1], mean[2])
|
||||
const center = Vec3.create(mean[0], mean[1], mean[2])
|
||||
|
||||
// normalized
|
||||
const van = Vec3.create(U.data[0], U.data[3], U.data[6])
|
||||
const vbn = Vec3.create(U.data[1], U.data[4], U.data[7])
|
||||
const vcn = Vec3.create(U.data[2], U.data[5], U.data[8])
|
||||
const normVecA = Vec3.create(U.data[0], U.data[3], U.data[6])
|
||||
const normVecB = Vec3.create(U.data[1], U.data[4], U.data[7])
|
||||
const normVecC = Vec3.create(U.data[2], U.data[5], U.data[8])
|
||||
|
||||
// scaled
|
||||
const va = Vec3.scale(Vec3.zero(), van, Math.sqrt(W.data[0] / n3))
|
||||
const vb = Vec3.scale(Vec3.zero(), vbn, Math.sqrt(W.data[1] / n3))
|
||||
const vc = Vec3.scale(Vec3.zero(), vcn, Math.sqrt(W.data[2] / n3))
|
||||
// const va = van.clone().multiplyScalar(Math.sqrt(W.data[0] / n3))
|
||||
// const vb = vbn.clone().multiplyScalar(Math.sqrt(W.data[1] / n3))
|
||||
// const vc = vcn.clone().multiplyScalar(Math.sqrt(W.data[2] / n3))
|
||||
const vecA = Vec3.scale(Vec3(), normVecA, Math.sqrt(W.data[0] / n3))
|
||||
const vecB = Vec3.scale(Vec3(), normVecB, Math.sqrt(W.data[1] / n3))
|
||||
const vecC = Vec3.scale(Vec3(), normVecC, Math.sqrt(W.data[2] / n3))
|
||||
|
||||
// points
|
||||
this.begA = Vec3.sub(Vec3.clone(vm), vm, va)
|
||||
this.endA = Vec3.add(Vec3.clone(vm), vm, va)
|
||||
this.begB = Vec3.sub(Vec3.clone(vm), vm, vb)
|
||||
this.endB = Vec3.add(Vec3.clone(vm), vm, vb)
|
||||
this.begC = Vec3.sub(Vec3.clone(vm), vm, vc)
|
||||
this.endC = Vec3.add(Vec3.clone(vm), vm, vc)
|
||||
// this.begA = vm.clone().sub(va)
|
||||
// this.endA = vm.clone().add(va)
|
||||
// this.begB = vm.clone().sub(vb)
|
||||
// this.endB = vm.clone().add(vb)
|
||||
// this.begC = vm.clone().sub(vc)
|
||||
// this.endC = vm.clone().add(vc)
|
||||
const begA = Vec3.sub(Vec3.clone(center), center, vecA)
|
||||
const endA = Vec3.add(Vec3.clone(center), center, vecA)
|
||||
const begB = Vec3.sub(Vec3.clone(center), center, vecB)
|
||||
const endB = Vec3.add(Vec3.clone(center), center, vecB)
|
||||
const begC = Vec3.sub(Vec3.clone(center), center, vecC)
|
||||
const endC = Vec3.add(Vec3.clone(center), center, vecC)
|
||||
|
||||
//
|
||||
|
||||
this.center = vm
|
||||
|
||||
this.vecA = va
|
||||
this.vecB = vb
|
||||
this.vecC = vc
|
||||
|
||||
this.normVecA = van
|
||||
this.normVecB = vbn
|
||||
this.normVecC = vcn
|
||||
return {
|
||||
begA, endA, begB, endB, begC, endC,
|
||||
center,
|
||||
vecA, vecB, vecC,
|
||||
normVecA, normVecB, normVecC
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// /**
|
||||
// * Get the basis matrix descriping the axes
|
||||
// * @param {Matrix4} [optionalTarget] - target object
|
||||
// * @return {Matrix4} the basis
|
||||
// */
|
||||
// getBasisMatrix(optionalTarget = new Matrix4()) {
|
||||
// const basis = optionalTarget
|
||||
/**
|
||||
* Set basis matrix for given axes
|
||||
*/
|
||||
export function setBasisMatrix(out: Mat4, principalAxes: PrincipalAxes) {
|
||||
Mat4.setAxes(out, principalAxes.normVecB, principalAxes.normVecA, principalAxes.normVecC)
|
||||
if (Mat4.determinant(out) < 0) Mat4.scaleUniformly(out, out, -1)
|
||||
return out
|
||||
}
|
||||
|
||||
// basis.makeBasis(this.normVecB, this.normVecA, this.normVecC)
|
||||
// if (basis.determinant() < 0) {
|
||||
// basis.scale(negateVector)
|
||||
// }
|
||||
/**
|
||||
* Get the scale/length for each dimension for a box around the axes
|
||||
* to enclose the given positions
|
||||
*/
|
||||
export function getProjectedScale(positions: NumberArray, principalAxes: PrincipalAxes) {
|
||||
let d1a = -Infinity
|
||||
let d1b = -Infinity
|
||||
let d2a = -Infinity
|
||||
let d2b = -Infinity
|
||||
let d3a = -Infinity
|
||||
let d3b = -Infinity
|
||||
|
||||
// return basis
|
||||
// }
|
||||
const p = Vec3()
|
||||
const t = Vec3()
|
||||
|
||||
// TODO
|
||||
// /**
|
||||
// * Get a quaternion descriping the axes rotation
|
||||
// * @param {Quaternion} [optionalTarget] - target object
|
||||
// * @return {Quaternion} the rotation
|
||||
// */
|
||||
// getRotationQuaternion(optionalTarget = new Quaternion()) {
|
||||
// const q = optionalTarget
|
||||
// q.setFromRotationMatrix(this.getBasisMatrix(tmpMatrix))
|
||||
const { center, normVecA, normVecB, normVecC } = principalAxes
|
||||
|
||||
// return q.inverse()
|
||||
// }
|
||||
for (let i = 0, il = positions.length; i < il; i += 3) {
|
||||
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecA, center)
|
||||
const dp1 = Vec3.dot(normVecA, Vec3.normalize(t, Vec3.sub(t, p, center)))
|
||||
const dt1 = Vec3.distance(p, center)
|
||||
if (dp1 > 0) {
|
||||
if (dt1 > d1a) d1a = dt1
|
||||
} else {
|
||||
if (dt1 > d1b) d1b = dt1
|
||||
}
|
||||
|
||||
// TODO
|
||||
// /**
|
||||
// * Get the scale/length for each dimension for a box around the axes
|
||||
// * to enclose the atoms of a structure
|
||||
// * @param {Structure|StructureView} structure - the structure
|
||||
// * @return {{d1a: Number, d2a: Number, d3a: Number, d1b: Number, d2b: Number, d3b: Number}} scale
|
||||
// */
|
||||
// getProjectedScaleForAtoms(structure: Structure) {
|
||||
// let d1a = -Infinity
|
||||
// let d1b = -Infinity
|
||||
// let d2a = -Infinity
|
||||
// let d2b = -Infinity
|
||||
// let d3a = -Infinity
|
||||
// let d3b = -Infinity
|
||||
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecB, center)
|
||||
const dp2 = Vec3.dot(normVecB, Vec3.normalize(t, Vec3.sub(t, p, center)))
|
||||
const dt2 = Vec3.distance(p, center)
|
||||
if (dp2 > 0) {
|
||||
if (dt2 > d2a) d2a = dt2
|
||||
} else {
|
||||
if (dt2 > d2b) d2b = dt2
|
||||
}
|
||||
|
||||
// const p = new Vector3()
|
||||
// const t = new Vector3()
|
||||
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecC, center)
|
||||
const dp3 = Vec3.dot(normVecC, Vec3.normalize(t, Vec3.sub(t, p, center)))
|
||||
const dt3 = Vec3.distance(p, center)
|
||||
if (dp3 > 0) {
|
||||
if (dt3 > d3a) d3a = dt3
|
||||
} else {
|
||||
if (dt3 > d3b) d3b = dt3
|
||||
}
|
||||
}
|
||||
|
||||
// const center = this.center
|
||||
// const ax1 = this.normVecA
|
||||
// const ax2 = this.normVecB
|
||||
// const ax3 = this.normVecC
|
||||
|
||||
// structure.eachAtom(function (ap: AtomProxy) {
|
||||
// projectPointOnVector(p.copy(ap as any), ax1, center) // TODO
|
||||
// const dp1 = t.subVectors(p, center).normalize().dot(ax1)
|
||||
// const dt1 = p.distanceTo(center)
|
||||
// if (dp1 > 0) {
|
||||
// if (dt1 > d1a) d1a = dt1
|
||||
// } else {
|
||||
// if (dt1 > d1b) d1b = dt1
|
||||
// }
|
||||
|
||||
// projectPointOnVector(p.copy(ap as any), ax2, center)
|
||||
// const dp2 = t.subVectors(p, center).normalize().dot(ax2)
|
||||
// const dt2 = p.distanceTo(center)
|
||||
// if (dp2 > 0) {
|
||||
// if (dt2 > d2a) d2a = dt2
|
||||
// } else {
|
||||
// if (dt2 > d2b) d2b = dt2
|
||||
// }
|
||||
|
||||
// projectPointOnVector(p.copy(ap as any), ax3, center)
|
||||
// const dp3 = t.subVectors(p, center).normalize().dot(ax3)
|
||||
// const dt3 = p.distanceTo(center)
|
||||
// if (dp3 > 0) {
|
||||
// if (dt3 > d3a) d3a = dt3
|
||||
// } else {
|
||||
// if (dt3 > d3b) d3b = dt3
|
||||
// }
|
||||
// })
|
||||
|
||||
// return {
|
||||
// d1a: d1a,
|
||||
// d2a: d2a,
|
||||
// d3a: d3a,
|
||||
// d1b: -d1b,
|
||||
// d2b: -d2b,
|
||||
// d3b: -d3b
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
export default PrincipalAxes
|
||||
return {
|
||||
d1a: d1a,
|
||||
d2a: d2a,
|
||||
d3a: d3a,
|
||||
d1b: -d1b,
|
||||
d2b: -d2b,
|
||||
d3b: -d3b
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/mol-model-formats/structure/_spec/cif-core.spec.ts
Normal file
70
src/mol-model-formats/structure/_spec/cif-core.spec.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { CIF } from '../../../mol-io/reader/cif';
|
||||
|
||||
const cifCoreString = `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.
|
||||
;
|
||||
|
||||
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'
|
||||
|
||||
_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
|
||||
`
|
||||
|
||||
describe('cif-core read', () => {
|
||||
it('frame', async () => {
|
||||
const parsed = await CIF.parseText(cifCoreString).run()
|
||||
if (parsed.isError) return
|
||||
const cifFile = parsed.result
|
||||
const block = cifFile.blocks[0]
|
||||
|
||||
expect(block.getField('cell_length_a')!.float(0)).toBe(11.0829)
|
||||
expect.assertions(1)
|
||||
});
|
||||
|
||||
it('schema', async () => {
|
||||
const parsed = await CIF.parseText(cifCoreString).run()
|
||||
if (parsed.isError) return
|
||||
const cifFile = parsed.result
|
||||
const block = cifFile.blocks[0]
|
||||
const cifCore = CIF.schema.cifCore(block)
|
||||
|
||||
expect(cifCore.cell.length_a.value(0)).toBe(11.0829)
|
||||
expect.assertions(1)
|
||||
});
|
||||
});
|
||||
@@ -30,7 +30,7 @@ export class EntityBuilder {
|
||||
}
|
||||
|
||||
getEntityId(compId: string, moleculeType: MoleculeType, chainId: string): string {
|
||||
if (moleculeType === MoleculeType.water) {
|
||||
if (moleculeType === MoleculeType.Water) {
|
||||
if (this.waterId === undefined) {
|
||||
this.set('water', 'Water')
|
||||
this.waterId = `${this.count}`
|
||||
|
||||
@@ -36,7 +36,7 @@ function getCategories(atoms: GroAtoms) {
|
||||
let currentAsymIndex = 0
|
||||
let currentAsymId = ''
|
||||
let currentSeqId = 0
|
||||
let prevMoleculeType = MoleculeType.unknown
|
||||
let prevMoleculeType = MoleculeType.Unknown
|
||||
let prevResidueNumber = -1
|
||||
|
||||
for (let i = 0, il = atoms.count; i < il; ++i) {
|
||||
|
||||
@@ -15,7 +15,6 @@ import { AtomicConformation, AtomicData, AtomicHierarchy, AtomicSegments, AtomsS
|
||||
import { getAtomicIndex } from '../../../mol-model/structure/model/properties/utils/atomic-index';
|
||||
import { ElementSymbol } from '../../../mol-model/structure/model/types';
|
||||
import { Entities } from '../../../mol-model/structure/model/properties/common';
|
||||
import { getAtomicRanges } from '../../../mol-model/structure/model/properties/utils/atomic-ranges';
|
||||
import { getAtomicDerivedData } from '../../../mol-model/structure/model/properties/utils/atomic-derived';
|
||||
import { FormatData } from './parser';
|
||||
|
||||
@@ -43,6 +42,15 @@ function findHierarchyOffsets(atom_site: AtomSite) {
|
||||
return { residues, chains };
|
||||
}
|
||||
|
||||
function substUndefinedColumn<T extends Table<any>>(table: T, a: keyof T, b: keyof T) {
|
||||
if (!(table as any)[a].isDefined) {
|
||||
(table as any)[a] = (table as any)[b];
|
||||
}
|
||||
if (!(table as any)[b].isDefined) {
|
||||
(table as any)[b] = (table as any)[a];
|
||||
}
|
||||
}
|
||||
|
||||
function createHierarchyData(atom_site: AtomSite, sourceIndex: Column<number>, offsets: { residues: ArrayLike<number>, chains: ArrayLike<number> }): AtomicData {
|
||||
const atoms = Table.ofColumns(AtomsSchema, {
|
||||
type_symbol: Column.ofArray({ array: Column.mapToArray(atom_site.type_symbol, ElementSymbol), schema: Column.Schema.Aliased<ElementSymbol>(Column.Schema.str) }),
|
||||
@@ -52,11 +60,20 @@ function createHierarchyData(atom_site: AtomSite, sourceIndex: Column<number>, o
|
||||
pdbx_formal_charge: atom_site.pdbx_formal_charge,
|
||||
sourceIndex
|
||||
});
|
||||
|
||||
const residues = Table.view(atom_site, ResiduesSchema, offsets.residues);
|
||||
// Optimize the numeric columns
|
||||
Table.columnToArray(residues, 'label_seq_id', Int32Array);
|
||||
Table.columnToArray(residues, 'auth_seq_id', Int32Array);
|
||||
|
||||
const chains = Table.view(atom_site, ChainsSchema, offsets.chains);
|
||||
|
||||
// Fix possibly missing auth_/label_ columns
|
||||
substUndefinedColumn(residues, 'label_seq_id', 'auth_seq_id');
|
||||
substUndefinedColumn(atoms, 'label_atom_id', 'auth_atom_id');
|
||||
substUndefinedColumn(residues, 'label_comp_id', 'auth_comp_id');
|
||||
substUndefinedColumn(chains, 'label_asym_id', 'auth_asym_id');
|
||||
|
||||
return { atoms, residues, chains };
|
||||
}
|
||||
|
||||
@@ -100,7 +117,6 @@ export function getAtomicHierarchyAndConformation(atom_site: AtomSite, sourceInd
|
||||
|
||||
const index = getAtomicIndex(hierarchyData, entities, hierarchySegments);
|
||||
const derived = getAtomicDerivedData(hierarchyData, index, formatData.chemicalComponentMap);
|
||||
const hierarchyRanges = getAtomicRanges(hierarchyData, hierarchySegments, conformation, index, derived.residue.moleculeType);
|
||||
const hierarchy: AtomicHierarchy = { ...hierarchyData, ...hierarchySegments, ...hierarchyRanges, index, derived };
|
||||
const hierarchy: AtomicHierarchy = { ...hierarchyData, ...hierarchySegments, index, derived };
|
||||
return { sameAsPrevious: false, hierarchy, conformation };
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import mmCIF_Format = ModelFormat.mmCIF
|
||||
import { memoize1 } from '../../../mol-util/memoize';
|
||||
import { ElementIndex, EntityIndex } from '../../../mol-model/structure/model';
|
||||
import { AtomSiteAnisotrop } from './anisotropic';
|
||||
import { getAtomicRanges } from '../../../mol-model/structure/model/properties/utils/atomic-ranges';
|
||||
|
||||
export async function _parse_mmCif(format: mmCIF_Format, ctx: RuntimeContext) {
|
||||
const formatData = getFormatData(format)
|
||||
@@ -53,11 +54,19 @@ function checkNonStandardCrystalFrame(format: mmCIF_Format, spacegroup: Spacegro
|
||||
return false;
|
||||
}
|
||||
|
||||
function getSpacegroupNameOrNumber(symmetry: mmCIF_Format['data']['symmetry']) {
|
||||
const groupNumber = symmetry['Int_Tables_number'].value(0);
|
||||
const groupName = symmetry['space_group_name_H-M'].value(0);
|
||||
if (!symmetry['Int_Tables_number'].isDefined) return groupName
|
||||
if (!symmetry['space_group_name_H-M'].isDefined) return groupNumber
|
||||
return groupName
|
||||
}
|
||||
|
||||
function getSpacegroup(format: mmCIF_Format): Spacegroup {
|
||||
const { symmetry, cell } = format.data;
|
||||
if (symmetry._rowCount === 0 || cell._rowCount === 0) return Spacegroup.ZeroP1;
|
||||
const groupName = symmetry['space_group_name_H-M'].value(0);
|
||||
const spaceCell = SpacegroupCell.create(groupName,
|
||||
const nameOrNumber = getSpacegroupNameOrNumber(symmetry)
|
||||
const spaceCell = SpacegroupCell.create(nameOrNumber,
|
||||
Vec3.create(cell.length_a.value(0), cell.length_b.value(0), cell.length_c.value(0)),
|
||||
Vec3.scale(Vec3.zero(), Vec3.create(cell.angle_alpha.value(0), cell.angle_beta.value(0), cell.angle_gamma.value(0)), Math.PI / 180));
|
||||
|
||||
@@ -171,7 +180,7 @@ function getSaccharideComponentMap(format: mmCIF_Format): SaccharideComponentMap
|
||||
const _type = type.value(i)
|
||||
if (SaccharideCompIdMap.has(_id)) {
|
||||
map.set(_id, SaccharideCompIdMap.get(_id)!)
|
||||
} else if (getMoleculeType(_type, _id) === MoleculeType.saccharide) {
|
||||
} else if (getMoleculeType(_type, _id) === MoleculeType.Saccharide) {
|
||||
map.set(_id, UnknownSaccharideComponent)
|
||||
}
|
||||
}
|
||||
@@ -224,6 +233,9 @@ function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, sourceIn
|
||||
}
|
||||
|
||||
const coarse = EmptyIHMCoarse;
|
||||
const sequence = getSequence(format.data, entities, atomic.hierarchy, coarse.hierarchy, formatData.modifiedResidues.parentId)
|
||||
const atomicRanges = getAtomicRanges(atomic.hierarchy, entities, atomic.conformation, sequence)
|
||||
|
||||
const entry = format.data.entry.id.valueKind(0) === Column.ValueKind.Present
|
||||
? format.data.entry.id.value(0)
|
||||
: format.data._name;
|
||||
@@ -241,9 +253,10 @@ function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, sourceIn
|
||||
modelNum,
|
||||
entities,
|
||||
symmetry: getSymmetry(format),
|
||||
sequence: getSequence(format.data, entities, atomic.hierarchy, coarse.hierarchy, formatData.modifiedResidues.parentId),
|
||||
sequence,
|
||||
atomicHierarchy: atomic.hierarchy,
|
||||
atomicConformation: atomic.conformation,
|
||||
atomicRanges,
|
||||
coarseHierarchy: coarse.hierarchy,
|
||||
coarseConformation: coarse.conformation,
|
||||
properties: {
|
||||
@@ -259,6 +272,9 @@ function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, sourceIn
|
||||
function createModelIHM(format: mmCIF_Format, data: IHMData, formatData: FormatData): Model {
|
||||
const atomic = getAtomicHierarchyAndConformation(data.atom_site, data.atom_site_sourceIndex, data.entities, formatData);
|
||||
const coarse = getIHMCoarse(data, formatData);
|
||||
const sequence = getSequence(format.data, data.entities, atomic.hierarchy, coarse.hierarchy, formatData.modifiedResidues.parentId)
|
||||
const atomicRanges = getAtomicRanges(atomic.hierarchy, data.entities, atomic.conformation, sequence)
|
||||
|
||||
const entry = format.data.entry.id.valueKind(0) === Column.ValueKind.Present
|
||||
? format.data.entry.id.value(0)
|
||||
: format.data._name;
|
||||
@@ -278,9 +294,10 @@ function createModelIHM(format: mmCIF_Format, data: IHMData, formatData: FormatD
|
||||
modelNum: data.model_id,
|
||||
entities: data.entities,
|
||||
symmetry: getSymmetry(format),
|
||||
sequence: getSequence(format.data, data.entities, atomic.hierarchy, coarse.hierarchy, formatData.modifiedResidues.parentId),
|
||||
sequence,
|
||||
atomicHierarchy: atomic.hierarchy,
|
||||
atomicConformation: atomic.conformation,
|
||||
atomicRanges,
|
||||
coarseHierarchy: coarse.hierarchy,
|
||||
coarseConformation: coarse.conformation,
|
||||
properties: {
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace CustomElementProperty {
|
||||
function LabelProvider(loci: Loci): string | undefined {
|
||||
if (loci.kind === 'element-loci') {
|
||||
const e = loci.elements[0];
|
||||
if (!has(e.unit.model)) return void 0;
|
||||
if (!e || !has(e.unit.model)) return void 0;
|
||||
return params.format!(get(StructureElement.Location.create(e.unit, e.unit.elements[OrderedSet.getAt(e.indices, 0)])));
|
||||
}
|
||||
return void 0;
|
||||
|
||||
@@ -55,7 +55,7 @@ export const AssemblySymmetryAxesRepresentationProvider: StructureRepresentation
|
||||
defaultValues: PD.getDefaultValues(AssemblySymmetryAxesParams),
|
||||
defaultColorTheme: 'uniform',
|
||||
defaultSizeTheme: 'uniform',
|
||||
isApplicable: (structure: Structure) => AssemblySymmetry.get(structure.models[0]) !== undefined
|
||||
isApplicable: (structure: Structure) => structure.models.length > 0 && AssemblySymmetry.get(structure.models[0]) !== undefined
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -12,18 +12,19 @@ import { CentroidHelper } from '../mol-math/geometry/centroid-helper';
|
||||
import { Vec3 } from '../mol-math/linear-algebra';
|
||||
import { OrderedSet } from '../mol-data/int';
|
||||
import { Structure } from './structure/structure';
|
||||
import { capitalize } from '../mol-util/string';
|
||||
|
||||
/** A Loci that includes every loci */
|
||||
export const EveryLoci = { kind: 'every-loci' as 'every-loci' }
|
||||
export type EveryLoci = typeof EveryLoci
|
||||
export function isEveryLoci(x: any): x is EveryLoci {
|
||||
export function isEveryLoci(x?: Loci): x is EveryLoci {
|
||||
return !!x && x.kind === 'every-loci';
|
||||
}
|
||||
|
||||
/** A Loci that is empty */
|
||||
export const EmptyLoci = { kind: 'empty-loci' as 'empty-loci' }
|
||||
export type EmptyLoci = typeof EmptyLoci
|
||||
export function isEmptyLoci(x: any): x is EmptyLoci {
|
||||
export function isEmptyLoci(x?: Loci): x is EmptyLoci {
|
||||
return !!x && x.kind === 'empty-loci';
|
||||
}
|
||||
|
||||
@@ -34,7 +35,7 @@ export interface DataLoci {
|
||||
readonly tag: string
|
||||
readonly indices: OrderedSet<number>
|
||||
}
|
||||
export function isDataLoci(x: any): x is DataLoci {
|
||||
export function isDataLoci(x?: Loci): x is DataLoci {
|
||||
return !!x && x.kind === 'data-loci';
|
||||
}
|
||||
export function areDataLociEqual(a: DataLoci, b: DataLoci) {
|
||||
@@ -76,7 +77,11 @@ namespace Loci {
|
||||
return false
|
||||
}
|
||||
|
||||
export function isEmpty(loci: Loci): boolean {
|
||||
export function isEvery(loci?: Loci): loci is EveryLoci {
|
||||
return !!loci && loci.kind === 'every-loci';
|
||||
}
|
||||
|
||||
export function isEmpty(loci: Loci): loci is EmptyLoci {
|
||||
if (isEveryLoci(loci)) return false
|
||||
if (isEmptyLoci(loci)) return true
|
||||
if (isDataLoci(loci)) return isDataLociEmpty(loci)
|
||||
@@ -92,6 +97,8 @@ namespace Loci {
|
||||
if (data instanceof Structure) {
|
||||
if (StructureElement.Loci.is(loci)) {
|
||||
loci = StructureElement.Loci.remap(loci, data)
|
||||
} else if (Structure.isLoci(loci)) {
|
||||
loci = Structure.remapLoci(loci, data)
|
||||
} else if (Link.isLoci(loci)) {
|
||||
loci = Link.remapLoci(loci, data)
|
||||
}
|
||||
@@ -146,4 +153,55 @@ namespace Loci {
|
||||
const boundingSphere = getBoundingSphere(loci, tmpSphere3D)
|
||||
return boundingSphere ? Vec3.copy(center || Vec3.zero(), boundingSphere.center) : undefined
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const Granularity = {
|
||||
'element': (loci: Loci) => loci,
|
||||
'residue': (loci: Loci) => {
|
||||
return StructureElement.Loci.is(loci)
|
||||
? StructureElement.Loci.extendToWholeResidues(loci, true)
|
||||
: loci
|
||||
},
|
||||
'chain': (loci: Loci) => {
|
||||
return StructureElement.Loci.is(loci)
|
||||
? StructureElement.Loci.extendToWholeChains(loci)
|
||||
: loci
|
||||
},
|
||||
'structure': (loci: Loci) => {
|
||||
return StructureElement.Loci.is(loci)
|
||||
? Structure.toStructureElementLoci(loci.structure)
|
||||
: loci
|
||||
}
|
||||
}
|
||||
export type Granularity = keyof typeof Granularity
|
||||
export const GranularityOptions = Object.keys(Granularity).map(n => [n, capitalize(n)]) as [Granularity, string][]
|
||||
|
||||
export function applyGranularity(loci: Loci, granularity: Granularity) {
|
||||
return Granularity[granularity](loci)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts structure related loci to StructureElement.Loci and applies
|
||||
* granularity if given
|
||||
*/
|
||||
export function normalize(loci: Loci, granularity?: Granularity) {
|
||||
if (granularity !== 'element' && Link.isLoci(loci)) {
|
||||
// convert Link.Loci to a StructureElement.Loci so granularity can be applied
|
||||
loci = Link.toStructureElementLoci(loci)
|
||||
}
|
||||
if (Structure.isLoci(loci)) {
|
||||
// convert to StructureElement.Loci
|
||||
loci = Structure.toStructureElementLoci(loci.structure)
|
||||
}
|
||||
if (StructureElement.Loci.is(loci)) {
|
||||
// ensure the root structure is used
|
||||
loci = StructureElement.Loci.remap(loci, loci.structure.root)
|
||||
}
|
||||
if (granularity) {
|
||||
// needs to be applied AFTER remapping to root
|
||||
loci = applyGranularity(loci, granularity)
|
||||
}
|
||||
return loci
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import UUID from '../../../mol-util/uuid';
|
||||
import StructureSequence from './properties/sequence';
|
||||
import { AtomicHierarchy, AtomicConformation } from './properties/atomic';
|
||||
import { AtomicHierarchy, AtomicConformation, AtomicRanges } from './properties/atomic';
|
||||
import { ModelSymmetry } from './properties/symmetry';
|
||||
import { CoarseHierarchy, CoarseConformation } from './properties/coarse';
|
||||
import { Entities, ChemicalComponentMap, MissingResidues } from './properties/common';
|
||||
@@ -42,6 +42,7 @@ export interface Model extends Readonly<{
|
||||
|
||||
atomicHierarchy: AtomicHierarchy,
|
||||
atomicConformation: AtomicConformation,
|
||||
atomicRanges: AtomicRanges,
|
||||
|
||||
properties: {
|
||||
/** secondary structure provided by the input file */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { Column, Table } from '../../../../../mol-data/db'
|
||||
import { Segmentation } from '../../../../../mol-data/int'
|
||||
import { mmCIF_Schema as mmCIF } from '../../../../../mol-io/reader/cif/schema/mmcif'
|
||||
import { ElementSymbol, MoleculeType } from '../../types'
|
||||
import { ElementSymbol, MoleculeType, PolymerType } from '../../types'
|
||||
import { ChainIndex, EntityIndex, ResidueIndex, ElementIndex } from '../../indexing';
|
||||
import SortedRanges from '../../../../../mol-data/int/sorted-ranges';
|
||||
|
||||
@@ -116,6 +116,7 @@ export interface AtomicDerivedData {
|
||||
readonly directionFromElementIndex: ArrayLike<ElementIndex | -1>
|
||||
readonly directionToElementIndex: ArrayLike<ElementIndex | -1>
|
||||
readonly moleculeType: ArrayLike<MoleculeType>
|
||||
readonly polymerType: ArrayLike<PolymerType>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +223,7 @@ export interface AtomicRanges {
|
||||
cyclicPolymerMap: Map<ResidueIndex, ResidueIndex>
|
||||
}
|
||||
|
||||
type _Hierarchy = AtomicData & AtomicSegments & AtomicRanges
|
||||
type _Hierarchy = AtomicData & AtomicSegments
|
||||
export interface AtomicHierarchy extends _Hierarchy {
|
||||
index: AtomicIndex
|
||||
derived: AtomicDerivedData
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
import { AtomicData } from '../atomic';
|
||||
import { AtomicIndex, AtomicDerivedData } from '../atomic/hierarchy';
|
||||
import { ElementIndex, ResidueIndex } from '../../indexing';
|
||||
import { MoleculeType, getMoleculeType, getComponentType } from '../../types';
|
||||
import { MoleculeType, getMoleculeType, getComponentType, PolymerType, getPolymerType } from '../../types';
|
||||
import { getAtomIdForAtomRole } from '../../../../../mol-model/structure/util';
|
||||
import { ChemicalComponentMap } from '../common';
|
||||
import { isProductionMode } from '../../../../../mol-util/debug';
|
||||
|
||||
export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemicalComponentMap: ChemicalComponentMap): AtomicDerivedData {
|
||||
const { label_comp_id, _rowCount: n } = data.residues
|
||||
@@ -18,39 +19,50 @@ export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemi
|
||||
const directionFromElementIndex = new Int32Array(n)
|
||||
const directionToElementIndex = new Int32Array(n)
|
||||
const moleculeType = new Uint8Array(n)
|
||||
const polymerType = new Uint8Array(n)
|
||||
|
||||
const moleculeTypeMap = new Map<string, MoleculeType>()
|
||||
const polymerTypeMap = new Map<string, PolymerType>()
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
for (let i = 0 as ResidueIndex; i < n; ++i) {
|
||||
const compId = label_comp_id.value(i)
|
||||
const chemCompMap = chemicalComponentMap
|
||||
|
||||
let molType: MoleculeType
|
||||
let polyType: PolymerType
|
||||
if (moleculeTypeMap.has(compId)) {
|
||||
molType = moleculeTypeMap.get(compId)!
|
||||
} else if (chemCompMap.has(compId)) {
|
||||
molType = getMoleculeType(chemCompMap.get(compId)!.type, compId)
|
||||
moleculeTypeMap.set(compId, molType)
|
||||
polyType = polymerTypeMap.get(compId)!
|
||||
} else {
|
||||
console.log('chemComp not found', compId)
|
||||
molType = getMoleculeType(getComponentType(compId), compId)
|
||||
let type: string
|
||||
if (chemCompMap.has(compId)) {
|
||||
type = chemCompMap.get(compId)!.type
|
||||
} else {
|
||||
if (!isProductionMode) console.info('chemComp not found', compId)
|
||||
type = getComponentType(compId)
|
||||
}
|
||||
molType = getMoleculeType(type, compId)
|
||||
// TODO if unknown molecule type, use atom names to guess molecule type
|
||||
polyType = getPolymerType(type, molType)
|
||||
moleculeTypeMap.set(compId, molType)
|
||||
polymerTypeMap.set(compId, polyType)
|
||||
}
|
||||
moleculeType[i] = molType
|
||||
polymerType[i] = polyType
|
||||
|
||||
const traceAtomId = getAtomIdForAtomRole(molType, 'trace')
|
||||
let traceIndex = index.findAtomsOnResidue(i as ResidueIndex, traceAtomId)
|
||||
const traceAtomId = getAtomIdForAtomRole(polyType, 'trace')
|
||||
let traceIndex = index.findAtomsOnResidue(i, traceAtomId)
|
||||
if (traceIndex === -1) {
|
||||
const coarseAtomId = getAtomIdForAtomRole(molType, 'coarseBackbone')
|
||||
traceIndex = index.findAtomsOnResidue(i as ResidueIndex, coarseAtomId)
|
||||
const coarseAtomId = getAtomIdForAtomRole(polyType, 'coarseBackbone')
|
||||
traceIndex = index.findAtomsOnResidue(i, coarseAtomId)
|
||||
}
|
||||
traceElementIndex[i] = traceIndex
|
||||
|
||||
const directionFromAtomId = getAtomIdForAtomRole(molType, 'directionFrom')
|
||||
directionFromElementIndex[i] = index.findAtomsOnResidue(i as ResidueIndex, directionFromAtomId)
|
||||
const directionFromAtomId = getAtomIdForAtomRole(polyType, 'directionFrom')
|
||||
directionFromElementIndex[i] = index.findAtomsOnResidue(i, directionFromAtomId)
|
||||
|
||||
const directionToAtomId = getAtomIdForAtomRole(molType, 'directionTo')
|
||||
directionToElementIndex[i] = index.findAtomsOnResidue(i as ResidueIndex, directionToAtomId)
|
||||
const directionToAtomId = getAtomIdForAtomRole(polyType, 'directionTo')
|
||||
directionToElementIndex[i] = index.findAtomsOnResidue(i, directionToAtomId)
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -59,6 +71,7 @@ export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemi
|
||||
directionFromElementIndex: directionFromElementIndex as unknown as ArrayLike<ElementIndex | -1>,
|
||||
directionToElementIndex: directionToElementIndex as unknown as ArrayLike<ElementIndex | -1>,
|
||||
moleculeType: moleculeType as unknown as ArrayLike<MoleculeType>,
|
||||
polymerType: polymerType as unknown as ArrayLike<PolymerType>,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { AtomicSegments } from '../atomic';
|
||||
import { AtomicData, AtomicRanges, AtomicIndex } from '../atomic/hierarchy';
|
||||
import { AtomicRanges, AtomicIndex, AtomicHierarchy, AtomicDerivedData } from '../atomic/hierarchy';
|
||||
import { Segmentation, Interval } from '../../../../../mol-data/int';
|
||||
import SortedRanges from '../../../../../mol-data/int/sorted-ranges';
|
||||
import { MoleculeType, isPolymer } from '../../types';
|
||||
import { isPolymer, PolymerType } from '../../types';
|
||||
import { ElementIndex, ResidueIndex } from '../../indexing';
|
||||
import { getAtomIdForAtomRole } from '../../../util';
|
||||
import { AtomicConformation } from '../atomic/conformation';
|
||||
import { Vec3 } from '../../../../../mol-math/linear-algebra';
|
||||
import { Entities } from '../common';
|
||||
import StructureSequence from '../sequence';
|
||||
|
||||
// TODO add gaps at the ends of the chains by comparing to the polymer sequence data
|
||||
function areBackboneConnected(riStart: ResidueIndex, riEnd: ResidueIndex, conformation: AtomicConformation, index: AtomicIndex, derived: AtomicDerivedData) {
|
||||
const { polymerType, traceElementIndex, directionFromElementIndex, directionToElementIndex } = derived.residue
|
||||
const ptStart = polymerType[riStart]
|
||||
const ptEnd = polymerType[riEnd]
|
||||
if (ptStart === PolymerType.NA || ptEnd === PolymerType.NA) return false
|
||||
if (traceElementIndex[riStart] === -1 || traceElementIndex[riEnd] === -1) return false
|
||||
|
||||
function areBackboneConnected(riStart: ResidueIndex, riEnd: ResidueIndex, data: AtomicData, segments: AtomicSegments, conformation: AtomicConformation, index: AtomicIndex, moleculeType: ArrayLike<MoleculeType>) {
|
||||
const mtStart = moleculeType[riStart]
|
||||
const mtEnd = moleculeType[riEnd]
|
||||
if (!isPolymer(mtStart) || !isPolymer(mtEnd)) return false
|
||||
|
||||
let eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(mtStart, 'backboneStart'))
|
||||
let eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(mtEnd, 'backboneEnd'))
|
||||
let eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(ptStart, 'backboneStart'))
|
||||
let eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(ptEnd, 'backboneEnd'))
|
||||
|
||||
if (eiStart === -1 || eiEnd === -1) {
|
||||
eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(mtStart, 'coarseBackbone'))
|
||||
eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(mtEnd, 'coarseBackbone'))
|
||||
eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(ptStart, 'coarseBackbone'))
|
||||
eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(ptEnd, 'coarseBackbone'))
|
||||
}
|
||||
|
||||
const { x, y, z } = conformation
|
||||
const pStart = Vec3.create(x[eiStart], y[eiStart], z[eiStart])
|
||||
const pEnd = Vec3.create(x[eiEnd], y[eiEnd], z[eiEnd])
|
||||
return Vec3.distance(pStart, pEnd) < 10 // TODO better distance check, take into account if protein/nucleic and if coarse
|
||||
const isCoarse = directionFromElementIndex[riStart] === -1 || directionToElementIndex[riStart] === -1 || directionFromElementIndex[riEnd] === -1 || directionToElementIndex[riEnd] === -1
|
||||
return Vec3.distance(pStart, pEnd) < (isCoarse ? 10 : 3)
|
||||
}
|
||||
|
||||
export function getAtomicRanges(data: AtomicData, segments: AtomicSegments, conformation: AtomicConformation, index: AtomicIndex, moleculeType: ArrayLike<MoleculeType>): AtomicRanges {
|
||||
export function getAtomicRanges(hierarchy: AtomicHierarchy, entities: Entities, conformation: AtomicConformation, sequence: StructureSequence): AtomicRanges {
|
||||
const polymerRanges: number[] = []
|
||||
const gapRanges: number[] = []
|
||||
const cyclicPolymerMap = new Map<ResidueIndex, ResidueIndex>()
|
||||
const chainIt = Segmentation.transientSegments(segments.chainAtomSegments, Interval.ofBounds(0, data.atoms._rowCount))
|
||||
const residueIt = Segmentation.transientSegments(segments.residueAtomSegments, Interval.ofBounds(0, data.atoms._rowCount))
|
||||
const { label_seq_id } = data.residues
|
||||
const chainIt = Segmentation.transientSegments(hierarchy.chainAtomSegments, Interval.ofBounds(0, hierarchy.atoms._rowCount))
|
||||
const residueIt = Segmentation.transientSegments(hierarchy.residueAtomSegments, Interval.ofBounds(0, hierarchy.atoms._rowCount))
|
||||
const { index, derived } = hierarchy
|
||||
const { label_seq_id } = hierarchy.residues
|
||||
const { label_entity_id } = hierarchy.chains
|
||||
const { moleculeType, traceElementIndex } = derived.residue
|
||||
|
||||
let prevSeqId: number
|
||||
let prevStart: number
|
||||
@@ -56,9 +61,16 @@ export function getAtomicRanges(data: AtomicData, segments: AtomicSegments, conf
|
||||
prevEnd = -1
|
||||
startIndex = -1
|
||||
|
||||
const riStart = segments.residueAtomSegments.index[chainSegment.start]
|
||||
const riEnd = segments.residueAtomSegments.index[chainSegment.end - 1]
|
||||
if (areBackboneConnected(riStart, riEnd, data, segments, conformation, index, moleculeType)) {
|
||||
const eI = entities.getEntityIndex(label_entity_id.value(chainSegment.index))
|
||||
const seq = sequence.byEntityKey[eI]
|
||||
const maxSeqId = seq ? seq.sequence.seqId.value(seq.sequence.seqId.rowCount - 1) : -1
|
||||
|
||||
// check cyclic peptides, seqIds and distance must be compatible
|
||||
const riStart = hierarchy.residueAtomSegments.index[chainSegment.start]
|
||||
const riEnd = hierarchy.residueAtomSegments.index[chainSegment.end - 1]
|
||||
const seqIdStart = label_seq_id.value(riStart)
|
||||
const seqIdEnd = label_seq_id.value(riEnd)
|
||||
if (seqIdStart === 1 && seqIdEnd === maxSeqId && areBackboneConnected(riStart, riEnd, conformation, index, derived)) {
|
||||
cyclicPolymerMap.set(riStart, riEnd)
|
||||
cyclicPolymerMap.set(riEnd, riStart)
|
||||
}
|
||||
@@ -67,7 +79,8 @@ export function getAtomicRanges(data: AtomicData, segments: AtomicSegments, conf
|
||||
const residueSegment = residueIt.move();
|
||||
const residueIndex = residueSegment.index
|
||||
const seqId = label_seq_id.value(residueIndex)
|
||||
if (isPolymer(moleculeType[residueIndex])) {
|
||||
// treat polymers residues that don't have a trace element resolved as gaps
|
||||
if (isPolymer(moleculeType[residueIndex]) && traceElementIndex[residueIndex] !== -1) {
|
||||
if (startIndex !== -1) {
|
||||
if (seqId !== prevSeqId + 1) {
|
||||
polymerRanges.push(startIndex, prevEnd - 1)
|
||||
@@ -75,16 +88,24 @@ export function getAtomicRanges(data: AtomicData, segments: AtomicSegments, conf
|
||||
startIndex = residueSegment.start
|
||||
} else if (!residueIt.hasNext) {
|
||||
polymerRanges.push(startIndex, residueSegment.end - 1)
|
||||
// TODO
|
||||
// if (seqId !== maxSeqId) {
|
||||
// gapRanges.push(residueSegment.end - 1, residueSegment.end - 1)
|
||||
// }
|
||||
} else {
|
||||
const riStart = segments.residueAtomSegments.index[residueSegment.start]
|
||||
const riEnd = segments.residueAtomSegments.index[prevEnd - 1]
|
||||
if (!areBackboneConnected(riStart, riEnd, data, segments, conformation, index, moleculeType)) {
|
||||
const riStart = hierarchy.residueAtomSegments.index[residueSegment.start]
|
||||
const riEnd = hierarchy.residueAtomSegments.index[prevEnd - 1]
|
||||
if (!areBackboneConnected(riStart, riEnd, conformation, hierarchy.index, derived)) {
|
||||
polymerRanges.push(startIndex, prevEnd - 1)
|
||||
startIndex = residueSegment.start
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startIndex = residueSegment.start // start polymer
|
||||
// TODO
|
||||
// if (seqId !== 1) {
|
||||
// gapRanges.push(residueSegment.start, residueSegment.start)
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
if (startIndex !== -1) {
|
||||
|
||||
@@ -40,30 +40,49 @@ export const enum EntityType {
|
||||
}
|
||||
|
||||
export const enum MoleculeType {
|
||||
/** the molecule type is not known */
|
||||
unknown,
|
||||
/** a known, but here not listed molecule type */
|
||||
other,
|
||||
/** water molecule */
|
||||
water,
|
||||
/** small ionic molecule */
|
||||
ion,
|
||||
/** protein, e.g. component type included in `ProteinComponentTypeNames` */
|
||||
protein,
|
||||
/** The molecule type is not known */
|
||||
Unknown,
|
||||
/** A known, but here not listed molecule type */
|
||||
Other,
|
||||
/** Water molecule */
|
||||
Water,
|
||||
/** Small ionic molecule */
|
||||
Ion,
|
||||
/** Protein, e.g. component type included in `ProteinComponentTypeNames` */
|
||||
Protein,
|
||||
/** RNA, e.g. component type included in `RNAComponentTypeNames` */
|
||||
RNA,
|
||||
/** DNA, e.g. component type included in `DNAComponentTypeNames` */
|
||||
DNA,
|
||||
/** PNA, peptide nucleic acid, comp id included in `PeptideBaseNames` */
|
||||
PNA,
|
||||
/** sacharide, e.g. component type included in `SaccharideComponentTypeNames` */
|
||||
saccharide
|
||||
/** Saccharide, e.g. component type included in `SaccharideComponentTypeNames` */
|
||||
Saccharide
|
||||
}
|
||||
|
||||
export const enum PolymerType {
|
||||
/** not applicable */
|
||||
NA,
|
||||
Protein,
|
||||
GammaProtein,
|
||||
BetaProtein,
|
||||
RNA,
|
||||
DNA,
|
||||
PNA,
|
||||
}
|
||||
|
||||
export type AtomRole = 'trace' | 'directionFrom' | 'directionTo' | 'backboneStart' | 'backboneEnd' | 'coarseBackbone'
|
||||
|
||||
export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<string> } } = {
|
||||
[MoleculeType.protein]: {
|
||||
export const PolymerTypeAtomRoleId: { [k in PolymerType]: { [k in AtomRole]: Set<string> } } = {
|
||||
[PolymerType.NA]: {
|
||||
trace: new Set(),
|
||||
directionFrom: new Set(),
|
||||
directionTo: new Set(),
|
||||
backboneStart: new Set(),
|
||||
backboneEnd: new Set(),
|
||||
coarseBackbone: new Set()
|
||||
},
|
||||
[PolymerType.Protein]: {
|
||||
trace: new Set(['CA']),
|
||||
directionFrom: new Set(['C']),
|
||||
directionTo: new Set(['O', 'OC1', 'O1', 'OX1', 'OXT']),
|
||||
@@ -73,7 +92,23 @@ export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<strin
|
||||
// BB is often used for coarse grained models
|
||||
coarseBackbone: new Set(['CA', 'BB', 'CA1'])
|
||||
},
|
||||
[MoleculeType.RNA]: {
|
||||
[PolymerType.GammaProtein]: {
|
||||
trace: new Set(['CA']),
|
||||
directionFrom: new Set(['C']),
|
||||
directionTo: new Set(['O']),
|
||||
backboneStart: new Set(['N']),
|
||||
backboneEnd: new Set(['CD']),
|
||||
coarseBackbone: new Set(['CA'])
|
||||
},
|
||||
[PolymerType.BetaProtein]: {
|
||||
trace: new Set(['CA']),
|
||||
directionFrom: new Set(['C']),
|
||||
directionTo: new Set(['O']),
|
||||
backboneStart: new Set(['N']),
|
||||
backboneEnd: new Set(['CG']),
|
||||
coarseBackbone: new Set(['CA'])
|
||||
},
|
||||
[PolymerType.RNA]: {
|
||||
trace: new Set(['C4\'', 'C4*']),
|
||||
directionFrom: new Set(['C4\'', 'C4*']),
|
||||
directionTo: new Set(['C3\'', 'C3*']),
|
||||
@@ -81,7 +116,7 @@ export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<strin
|
||||
backboneEnd: new Set(['O3\'', 'O3*']),
|
||||
coarseBackbone: new Set(['P'])
|
||||
},
|
||||
[MoleculeType.DNA]: {
|
||||
[PolymerType.DNA]: {
|
||||
trace: new Set(['C3\'', 'C3*']),
|
||||
directionFrom: new Set(['C3\'', 'C3*']),
|
||||
directionTo: new Set(['C1\'', 'C1*']),
|
||||
@@ -89,7 +124,7 @@ export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<strin
|
||||
backboneEnd: new Set(['O3\'', 'O3*']),
|
||||
coarseBackbone: new Set(['P'])
|
||||
},
|
||||
[MoleculeType.PNA]: {
|
||||
[PolymerType.PNA]: {
|
||||
trace: new Set(['N4\'', 'N4*']),
|
||||
directionFrom: new Set(['N4\'', 'N4*']),
|
||||
directionTo: new Set(['C7\'', 'C7*']),
|
||||
@@ -127,6 +162,16 @@ export const LProteinComponentTypeNames = new Set([
|
||||
'L-BETA-PEPTIDE, C-GAMMA LINKING'
|
||||
])
|
||||
|
||||
/** Chemical component type names for gamma protein, overlaps with D/L-linked */
|
||||
export const GammaProteinComponentTypeNames = new Set([
|
||||
'D-GAMMA-PEPTIDE, C-DELTA LINKING', 'L-GAMMA-PEPTIDE, C-DELTA LINKING'
|
||||
])
|
||||
|
||||
/** Chemical component type names for beta protein, overlaps with D/L-linked */
|
||||
export const BetaProteinComponentTypeNames = new Set([
|
||||
'D-BETA-PEPTIDE, C-GAMMA LINKING', 'L-BETA-PEPTIDE, C-GAMMA LINKING'
|
||||
])
|
||||
|
||||
/** Chemical component type names for pepdite-like protein */
|
||||
export const OtherProteinComponentTypeNames = new Set([
|
||||
'PEPTIDE LINKING', 'PEPTIDE-LIKE',
|
||||
@@ -206,32 +251,53 @@ export const isPyrimidineBase = (compId: string) => PyrimidineBaseNames.has(comp
|
||||
export const PolymerNames = SetUtils.unionMany(AminoAcidNames, BaseNames)
|
||||
|
||||
/** get the molecule type from component type and id */
|
||||
export function getMoleculeType(compType: string, compId: string) {
|
||||
export function getMoleculeType(compType: string, compId: string): MoleculeType {
|
||||
compType = compType.toUpperCase()
|
||||
compId = compId.toUpperCase()
|
||||
if (PeptideBaseNames.has(compId)) {
|
||||
return MoleculeType.PNA
|
||||
} else if (ProteinComponentTypeNames.has(compType)) {
|
||||
return MoleculeType.protein
|
||||
return MoleculeType.Protein
|
||||
} else if (RNAComponentTypeNames.has(compType)) {
|
||||
return MoleculeType.RNA
|
||||
} else if (DNAComponentTypeNames.has(compType)) {
|
||||
return MoleculeType.DNA
|
||||
} else if (SaccharideComponentTypeNames.has(compType)) {
|
||||
return MoleculeType.saccharide
|
||||
return MoleculeType.Saccharide
|
||||
} else if (WaterNames.has(compId)) {
|
||||
return MoleculeType.water
|
||||
return MoleculeType.Water
|
||||
} else if (IonNames.has(compId)) {
|
||||
return MoleculeType.ion
|
||||
return MoleculeType.Ion
|
||||
} else if (OtherComponentTypeNames.has(compType)) {
|
||||
if (SaccharideCompIdMap.has(compId)) {
|
||||
// trust our saccharide table more than given 'non-polymer' or 'other' component type
|
||||
return MoleculeType.saccharide
|
||||
return MoleculeType.Saccharide
|
||||
} else {
|
||||
return MoleculeType.other
|
||||
return MoleculeType.Other
|
||||
}
|
||||
} else {
|
||||
return MoleculeType.unknown
|
||||
return MoleculeType.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
export function getPolymerType(compType: string, molType: MoleculeType): PolymerType {
|
||||
compType = compType.toUpperCase()
|
||||
if (molType === MoleculeType.Protein) {
|
||||
if (GammaProteinComponentTypeNames.has(compType)) {
|
||||
return PolymerType.GammaProtein
|
||||
} else if (BetaProteinComponentTypeNames.has(compType)) {
|
||||
return PolymerType.BetaProtein
|
||||
} else {
|
||||
return PolymerType.Protein
|
||||
}
|
||||
} else if (molType === MoleculeType.RNA) {
|
||||
return PolymerType.RNA
|
||||
} else if (molType === MoleculeType.DNA) {
|
||||
return PolymerType.DNA
|
||||
} else if (molType === MoleculeType.PNA) {
|
||||
return PolymerType.PNA
|
||||
} else {
|
||||
return PolymerType.NA
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +382,7 @@ export function isNucleic(moleculeType: MoleculeType) {
|
||||
}
|
||||
|
||||
export function isProtein(moleculeType: MoleculeType) {
|
||||
return moleculeType === MoleculeType.protein
|
||||
return moleculeType === MoleculeType.Protein
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
import { Structure, StructureElement, Unit } from '../structure';
|
||||
import { now } from '../../../mol-util/now';
|
||||
import { ElementIndex } from '../model';
|
||||
import { Link } from '../structure/unit/links';
|
||||
import { LinkType } from '../model/types';
|
||||
import { StructureSelection } from './selection';
|
||||
import { defaultLinkTest } from './queries/internal';
|
||||
|
||||
export interface QueryContextView {
|
||||
readonly element: StructureElement.Location;
|
||||
@@ -31,7 +32,10 @@ export class QueryContext implements QueryContextView {
|
||||
currentStructure: Structure = void 0 as any;
|
||||
|
||||
/** Current link between atoms */
|
||||
readonly atomicLink = QueryContextLinkInfo.empty<Unit.Atomic>();
|
||||
readonly atomicLink = new QueryContextLinkInfo<Unit.Atomic>();
|
||||
|
||||
/** Supply this from the outside. Used by the internal.generator.current symbol */
|
||||
currentSelection: StructureSelection | undefined = void 0;
|
||||
|
||||
setElement(unit: Unit, e: ElementIndex) {
|
||||
this.element.unit = unit;
|
||||
@@ -50,7 +54,7 @@ export class QueryContext implements QueryContextView {
|
||||
|
||||
pushCurrentLink() {
|
||||
if (this.atomicLink) this.currentAtomicLinkStack.push(this.atomicLink);
|
||||
(this.atomicLink as QueryContextLinkInfo<Unit.Atomic>) = QueryContextLinkInfo.empty();
|
||||
(this.atomicLink as QueryContextLinkInfo<Unit.Atomic>) = new QueryContextLinkInfo();
|
||||
return this.atomicLink;
|
||||
}
|
||||
|
||||
@@ -88,23 +92,64 @@ export class QueryContext implements QueryContextView {
|
||||
}
|
||||
}
|
||||
|
||||
constructor(structure: Structure, timeoutMs = 0) {
|
||||
this.inputStructure = structure;
|
||||
this.timeoutMs = timeoutMs;
|
||||
tryGetCurrentSelection() {
|
||||
if (!this.currentSelection) throw new Error('The current selection is not assigned.');
|
||||
return this.currentSelection;
|
||||
}
|
||||
|
||||
constructor(structure: Structure, options?: QueryContextOptions) {
|
||||
this.inputStructure = structure;
|
||||
this.timeoutMs = (options && options.timeoutMs) || 0;
|
||||
this.currentSelection = options && options.currentSelection;
|
||||
}
|
||||
}
|
||||
|
||||
export interface QueryContextOptions {
|
||||
timeoutMs?: number,
|
||||
currentSelection?: StructureSelection
|
||||
}
|
||||
|
||||
export interface QueryPredicate { (ctx: QueryContext): boolean }
|
||||
export interface QueryFn<T = any> { (ctx: QueryContext): T }
|
||||
|
||||
export interface QueryContextLinkInfo<U extends Unit = Unit> {
|
||||
link: Link.Location<U>,
|
||||
type: LinkType,
|
||||
order: number
|
||||
}
|
||||
export class QueryContextLinkInfo<U extends Unit = Unit> {
|
||||
a: StructureElement.Location<U> = StructureElement.Location.create();
|
||||
aIndex: StructureElement.UnitIndex = 0 as StructureElement.UnitIndex;
|
||||
b: StructureElement.Location<U> = StructureElement.Location.create();
|
||||
bIndex: StructureElement.UnitIndex = 0 as StructureElement.UnitIndex;
|
||||
type: LinkType = LinkType.Flag.None;
|
||||
order: number = 0;
|
||||
|
||||
export namespace QueryContextLinkInfo {
|
||||
export function empty<U extends Unit = Unit>(): QueryContextLinkInfo<U> {
|
||||
return { link: Link.Location() as Link.Location<U>, type: LinkType.Flag.None, order: 0 };
|
||||
private testFn: QueryPredicate = defaultLinkTest;
|
||||
|
||||
setTestFn(fn?: QueryPredicate) {
|
||||
this.testFn = fn || defaultLinkTest;
|
||||
}
|
||||
|
||||
test(ctx: QueryContext, trySwap: boolean) {
|
||||
if (this.testFn(ctx)) return true;
|
||||
if (trySwap) {
|
||||
this.swap();
|
||||
return this.testFn(ctx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private swap() {
|
||||
const idxA = this.aIndex;
|
||||
this.aIndex = this.bIndex;
|
||||
this.bIndex = idxA;
|
||||
|
||||
const unitA = this.a.unit;
|
||||
this.a.unit = this.b.unit;
|
||||
this.b.unit = unitA;
|
||||
|
||||
const eA = this.a.element;
|
||||
this.a.element = this.b.element;
|
||||
this.b.element = eA;
|
||||
}
|
||||
|
||||
get length() {
|
||||
return StructureElement.Location.distance(this.a, this. b);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import { checkStructureMaxRadiusDistance, checkStructureMinMaxDistance } from '.
|
||||
import Structure from '../../structure/structure';
|
||||
import StructureElement from '../../structure/element';
|
||||
import { SortedArray } from '../../../../mol-data/int';
|
||||
import { defaultLinkTest } from './internal';
|
||||
|
||||
export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuery {
|
||||
return ctx => {
|
||||
@@ -230,14 +229,13 @@ function withinMinMaxRadius({ queryCtx, selection, target, minRadius, maxRadius,
|
||||
|
||||
interface IsConnectedToCtx {
|
||||
queryCtx: QueryContext,
|
||||
disjunct: boolean,
|
||||
input: Structure,
|
||||
target: Structure,
|
||||
linkTest: QueryFn<boolean>,
|
||||
tElement: StructureElement.Location
|
||||
target: Structure
|
||||
}
|
||||
|
||||
function checkConnected(ctx: IsConnectedToCtx, structure: Structure) {
|
||||
const { queryCtx, input, target, linkTest, tElement } = ctx;
|
||||
const { queryCtx, input, target, disjunct } = ctx;
|
||||
const atomicLink = queryCtx.atomicLink;
|
||||
|
||||
const interLinks = input.links;
|
||||
@@ -250,7 +248,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) {
|
||||
const linkedUnits = interLinks.getLinkedUnits(unit);
|
||||
const luCount = linkedUnits.length;
|
||||
|
||||
atomicLink.link.aUnit = inputUnit;
|
||||
atomicLink.a.unit = inputUnit;
|
||||
|
||||
const srcElements = unit.elements;
|
||||
const inputElements = inputUnit.elements;
|
||||
@@ -258,33 +256,43 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) {
|
||||
for (let i = 0 as StructureElement.UnitIndex, _i = srcElements.length; i < _i; i++) {
|
||||
const inputIndex = SortedArray.indexOf(inputElements, srcElements[i]) as StructureElement.UnitIndex;
|
||||
|
||||
atomicLink.link.aIndex = inputIndex;
|
||||
atomicLink.link.bUnit = inputUnit;
|
||||
atomicLink.a.unit = inputUnit;
|
||||
atomicLink.b.unit = inputUnit;
|
||||
|
||||
tElement.unit = unit;
|
||||
// tElement.unit = unit;
|
||||
for (let l = offset[inputIndex], _l = offset[inputIndex + 1]; l < _l; l++) {
|
||||
tElement.element = inputElements[b[l]];
|
||||
if (!target.hasElement(tElement)) continue;
|
||||
atomicLink.link.bIndex = b[l] as StructureElement.UnitIndex;
|
||||
// tElement.element = inputElements[b[l]];
|
||||
atomicLink.b.element = inputUnit.elements[b[l]];
|
||||
if (disjunct && SortedArray.has(unit.elements, atomicLink.b.element)) continue;
|
||||
if (!target.hasElement(atomicLink.b)) continue;
|
||||
|
||||
atomicLink.aIndex = inputIndex;
|
||||
atomicLink.a.element = srcElements[i];
|
||||
atomicLink.bIndex = b[l] as StructureElement.UnitIndex;
|
||||
atomicLink.type = flags[l];
|
||||
atomicLink.order = order[l];
|
||||
if (linkTest(queryCtx)) return true;
|
||||
if (atomicLink.test(queryCtx, true)) return true;
|
||||
}
|
||||
|
||||
for (let li = 0; li < luCount; li++) {
|
||||
const lu = linkedUnits[li];
|
||||
tElement.unit = lu.unitB;
|
||||
atomicLink.link.bUnit = lu.unitB;
|
||||
const bElements = lu.unitB.elements;
|
||||
const bonds = lu.getBonds(inputIndex);
|
||||
for (let bi = 0, _bi = bonds.length; bi < _bi; bi++) {
|
||||
const bond = bonds[bi];
|
||||
tElement.element = bElements[bond.indexB];
|
||||
if (!target.hasElement(tElement)) continue;
|
||||
atomicLink.link.bIndex = bond.indexB;
|
||||
atomicLink.b.unit = lu.unitB;
|
||||
atomicLink.b.element = bElements[bond.indexB];
|
||||
if (!target.hasElement(atomicLink.b)) continue;
|
||||
if (disjunct && structure.hasElement(atomicLink.b)) continue;
|
||||
|
||||
atomicLink.a.unit = inputUnit;
|
||||
atomicLink.aIndex = inputIndex;
|
||||
atomicLink.a.element = srcElements[i];
|
||||
|
||||
atomicLink.bIndex = bond.indexB;
|
||||
atomicLink.type = bond.flag;
|
||||
atomicLink.order = bond.order;
|
||||
if (linkTest(queryCtx)) return true;
|
||||
if (atomicLink.test(queryCtx, true)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,15 +319,20 @@ export function isConnectedTo({ query, target, disjunct, invert, linkTest }: IsC
|
||||
const connCtx: IsConnectedToCtx = {
|
||||
queryCtx: ctx,
|
||||
input: ctx.inputStructure,
|
||||
target: StructureSelection.unionStructure(targetSel),
|
||||
linkTest: linkTest || defaultLinkTest,
|
||||
tElement: StructureElement.Location.create()
|
||||
disjunct,
|
||||
target: StructureSelection.unionStructure(targetSel)
|
||||
}
|
||||
|
||||
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
|
||||
ctx.pushCurrentLink();
|
||||
ctx.atomicLink.setTestFn(linkTest);
|
||||
|
||||
StructureSelection.forEach(selection, (s, sI) => {
|
||||
if (checkConnected(connCtx, s)) ret.add(s);
|
||||
if (checkConnected(connCtx, s)) {
|
||||
ret.add(s);
|
||||
} else if (invert) {
|
||||
ret.add(s);
|
||||
}
|
||||
if (sI % 5 === 0) ctx.throwIfTimedOut();
|
||||
})
|
||||
ctx.popCurrentLink();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { StructureQuery } from '../query'
|
||||
import { StructureSelection } from '../selection'
|
||||
import { Unit, StructureProperties as P } from '../../structure'
|
||||
import { Unit, StructureProperties as P, StructureElement } from '../../structure'
|
||||
import { Segmentation, SortedArray } from '../../../../mol-data/int'
|
||||
import { LinearGroupingBuilder } from '../utils/builders';
|
||||
import { QueryPredicate, QueryFn, QueryContextView } from '../context';
|
||||
@@ -58,7 +58,7 @@ export function atoms(params?: Partial<AtomsQueryParams>): StructureQuery {
|
||||
}
|
||||
|
||||
function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_atomGroupsLinear(ctx) {
|
||||
const { inputStructure } = ctx;
|
||||
const { units } = inputStructure;
|
||||
const l = ctx.pushCurrentElement();
|
||||
@@ -83,7 +83,7 @@ function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
|
||||
}
|
||||
|
||||
function atomGroupsSegmented({ unitTest, entityTest, chainTest, residueTest, atomTest }: AtomsQueryParams): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_atomGroupsSegmented(ctx) {
|
||||
const { inputStructure } = ctx;
|
||||
const { units } = inputStructure;
|
||||
const l = ctx.pushCurrentElement();
|
||||
@@ -152,7 +152,7 @@ function atomGroupsSegmented({ unitTest, entityTest, chainTest, residueTest, ato
|
||||
}
|
||||
|
||||
function atomGroupsGrouped({ unitTest, entityTest, chainTest, residueTest, atomTest, groupBy }: AtomsQueryParams): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_atomGroupsGrouped(ctx) {
|
||||
const { inputStructure } = ctx;
|
||||
const { units } = inputStructure;
|
||||
const l = ctx.pushCurrentElement();
|
||||
@@ -224,9 +224,9 @@ function getRingStructure(unit: Unit.Atomic, ring: UnitRing, inputStructure: Str
|
||||
}
|
||||
|
||||
export function rings(fingerprints?: ArrayLike<UnitRing.Fingerprint>): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_rings(ctx) {
|
||||
const { units } = ctx.inputStructure;
|
||||
let ret = StructureSelection.LinearBuilder(ctx.inputStructure);
|
||||
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
|
||||
|
||||
if (!fingerprints || fingerprints.length === 0) {
|
||||
for (const u of units) {
|
||||
@@ -258,7 +258,7 @@ export function rings(fingerprints?: ArrayLike<UnitRing.Fingerprint>): Structure
|
||||
}
|
||||
|
||||
export function querySelection(selection: StructureQuery, query: StructureQuery, inComplement: boolean = false): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_querySelection(ctx) {
|
||||
const targetSel = selection(ctx);
|
||||
if (StructureSelection.structureCount(targetSel) === 0) return targetSel;
|
||||
|
||||
@@ -274,4 +274,71 @@ export function querySelection(selection: StructureQuery, query: StructureQuery,
|
||||
ctx.popInputStructure();
|
||||
return StructureSelection.withInputStructure(result, ctx.inputStructure);
|
||||
}
|
||||
}
|
||||
|
||||
export function linkedAtomicPairs(linkTest?: QueryPredicate): StructureQuery {
|
||||
return function query_linkedAtomicPairs(ctx) {
|
||||
const structure = ctx.inputStructure;
|
||||
|
||||
const interLinks = structure.links;
|
||||
// Note: each link is called twice, that's why we need the unique builder.
|
||||
const ret = StructureSelection.UniqueBuilder(ctx.inputStructure);
|
||||
|
||||
ctx.pushCurrentLink();
|
||||
const atomicLink = ctx.atomicLink;
|
||||
atomicLink.setTestFn(linkTest);
|
||||
|
||||
// Process intra unit links
|
||||
for (const unit of structure.units) {
|
||||
if (unit.kind !== Unit.Kind.Atomic) continue;
|
||||
|
||||
const { offset: intraLinkOffset, b: intraLinkB, edgeProps: { flags, order } } = unit.links;
|
||||
atomicLink.a.unit = unit;
|
||||
atomicLink.b.unit = unit;
|
||||
for (let i = 0 as StructureElement.UnitIndex, _i = unit.elements.length; i < _i; i++) {
|
||||
atomicLink.aIndex = i as StructureElement.UnitIndex;
|
||||
atomicLink.a.element = unit.elements[i];
|
||||
|
||||
// check intra unit links
|
||||
for (let lI = intraLinkOffset[i], _lI = intraLinkOffset[i + 1]; lI < _lI; lI++) {
|
||||
atomicLink.bIndex = intraLinkB[lI] as StructureElement.UnitIndex;
|
||||
atomicLink.b.element = unit.elements[intraLinkB[lI]];
|
||||
atomicLink.type = flags[lI];
|
||||
atomicLink.order = order[lI];
|
||||
// No need to "swap test" because each bond direction will be visited eventually.
|
||||
if (atomicLink.test(ctx, false)) {
|
||||
const b = structure.subsetBuilder(false);
|
||||
b.beginUnit(unit.id);
|
||||
b.addElement(atomicLink.a.element);
|
||||
b.addElement(atomicLink.b.element);
|
||||
b.commitUnit();
|
||||
ret.add(b.getStructure());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process inter unit links
|
||||
for (const bond of interLinks.bonds) {
|
||||
atomicLink.a.unit = bond.unitA;
|
||||
atomicLink.a.element = bond.unitA.elements[bond.indexA];
|
||||
atomicLink.aIndex = bond.indexA;
|
||||
atomicLink.b.unit = bond.unitB;
|
||||
atomicLink.b.element = bond.unitB.elements[bond.indexB];
|
||||
atomicLink.bIndex = bond.indexB;
|
||||
atomicLink.order = bond.order;
|
||||
atomicLink.type = bond.flag;
|
||||
|
||||
// No need to "swap test" because each bond direction will be visited eventually.
|
||||
if (atomicLink.test(ctx, false)) {
|
||||
const b = structure.subsetBuilder(false);
|
||||
b.addToUnit(atomicLink.a.unit.id, atomicLink.a.element);
|
||||
b.addToUnit(atomicLink.b.unit.id, atomicLink.b.element);
|
||||
ret.add(b.getStructure());
|
||||
}
|
||||
}
|
||||
|
||||
ctx.popCurrentLink();
|
||||
return ret.getSelection();
|
||||
};
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Segmentation } from '../../../../mol-data/int';
|
||||
import { Segmentation, SortedArray } from '../../../../mol-data/int';
|
||||
import StructureElement from '../../../../mol-model/structure/structure/element';
|
||||
import { StructureProperties as P, Unit } from '../../structure';
|
||||
import Structure from '../../structure/structure';
|
||||
@@ -12,13 +12,15 @@ import { StructureQuery } from '../query';
|
||||
import { StructureSelection } from '../selection';
|
||||
import { QueryContext } from '../context';
|
||||
import { LinkType } from '../../model/types';
|
||||
import { BundleElement, Bundle } from '../../structure/element/bundle';
|
||||
import { UnitIndex } from '../../structure/element/element';
|
||||
|
||||
export function defaultLinkTest(ctx: QueryContext) {
|
||||
return LinkType.isCovalent(ctx.atomicLink.type);
|
||||
}
|
||||
|
||||
export function atomicSequence(): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_atomicSequence(ctx) {
|
||||
const { inputStructure } = ctx;
|
||||
const l = StructureElement.Location.create();
|
||||
|
||||
@@ -46,7 +48,7 @@ export function atomicSequence(): StructureQuery {
|
||||
}
|
||||
|
||||
export function water(): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_water(ctx) {
|
||||
const { inputStructure } = ctx;
|
||||
const l = StructureElement.Location.create();
|
||||
|
||||
@@ -65,7 +67,7 @@ export function water(): StructureQuery {
|
||||
}
|
||||
|
||||
export function atomicHet(): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_atomicHet(ctx) {
|
||||
const { inputStructure } = ctx;
|
||||
const l = StructureElement.Location.create();
|
||||
|
||||
@@ -95,7 +97,7 @@ export function atomicHet(): StructureQuery {
|
||||
}
|
||||
|
||||
export function spheres(): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_spheres(ctx) {
|
||||
const { inputStructure } = ctx;
|
||||
|
||||
const units: Unit[] = [];
|
||||
@@ -105,4 +107,23 @@ export function spheres(): StructureQuery {
|
||||
}
|
||||
return StructureSelection.Singletons(inputStructure, new Structure(units, { parent: inputStructure }));
|
||||
};
|
||||
}
|
||||
|
||||
export function bundleElementImpl(groupedUnits: number[][], ranges: number[], set: number[]): BundleElement {
|
||||
return {
|
||||
groupedUnits: groupedUnits as any as SortedArray<number>[],
|
||||
ranges: ranges as any as SortedArray<UnitIndex>,
|
||||
set: set as any as SortedArray<UnitIndex>
|
||||
};
|
||||
}
|
||||
|
||||
export function bundleGenerator(elements: BundleElement[]): StructureQuery {
|
||||
return function query_bundleGenerator(ctx) {
|
||||
const bundle: Bundle = {
|
||||
hash: ctx.inputStructure.hashCode,
|
||||
elements
|
||||
};
|
||||
|
||||
return StructureSelection.Sequence(ctx.inputStructure, [Bundle.toStructure(bundle, ctx.inputStructure)]);
|
||||
};
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import { structureIntersect, structureSubtract } from '../utils/structure-set';
|
||||
import { UniqueArray } from '../../../../mol-data/generic';
|
||||
import { StructureSubsetBuilder } from '../../structure/util/subset-builder';
|
||||
import StructureElement from '../../structure/element';
|
||||
import { defaultLinkTest } from './internal';
|
||||
|
||||
function getWholeResidues(ctx: QueryContext, source: Structure, structure: Structure) {
|
||||
const builder = source.subsetBuilder(true);
|
||||
@@ -45,7 +44,7 @@ function getWholeResidues(ctx: QueryContext, source: Structure, structure: Struc
|
||||
}
|
||||
|
||||
export function wholeResidues(query: StructureQuery): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_wholeResidues(ctx) {
|
||||
const inner = query(ctx);
|
||||
if (StructureSelection.isSingleton(inner)) {
|
||||
return StructureSelection.Singletons(ctx.inputStructure, getWholeResidues(ctx, ctx.inputStructure, inner.structure));
|
||||
@@ -141,7 +140,7 @@ function findStructureRadius(ctx: QueryContext, eRadius: QueryFn<number>) {
|
||||
}
|
||||
|
||||
export function includeSurroundings(query: StructureQuery, params: IncludeSurroundingsParams): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_includeSurroundings(ctx) {
|
||||
const inner = query(ctx);
|
||||
|
||||
if (params.elementRadius) {
|
||||
@@ -180,7 +179,7 @@ export function includeSurroundings(query: StructureQuery, params: IncludeSurrou
|
||||
}
|
||||
|
||||
export function querySelection(selection: StructureQuery, query: StructureQuery): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_querySelection(ctx) {
|
||||
const targetSel = selection(ctx);
|
||||
if (StructureSelection.structureCount(targetSel) === 0) return targetSel;
|
||||
|
||||
@@ -198,7 +197,7 @@ export function querySelection(selection: StructureQuery, query: StructureQuery)
|
||||
}
|
||||
|
||||
export function intersectBy(query: StructureQuery, by: StructureQuery): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_intersectBy(ctx) {
|
||||
const selection = query(ctx);
|
||||
if (StructureSelection.structureCount(selection) === 0) return selection;
|
||||
|
||||
@@ -218,7 +217,7 @@ export function intersectBy(query: StructureQuery, by: StructureQuery): Structur
|
||||
}
|
||||
|
||||
export function exceptBy(query: StructureQuery, by: StructureQuery): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_exceptBy(ctx) {
|
||||
const selection = query(ctx);
|
||||
if (StructureSelection.structureCount(selection) === 0) return selection;
|
||||
|
||||
@@ -238,7 +237,7 @@ export function exceptBy(query: StructureQuery, by: StructureQuery): StructureQu
|
||||
}
|
||||
|
||||
export function union(query: StructureQuery): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_union(ctx) {
|
||||
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
|
||||
ret.add(StructureSelection.unionStructure(query(ctx)));
|
||||
return ret.getSelection();
|
||||
@@ -246,7 +245,7 @@ export function union(query: StructureQuery): StructureQuery {
|
||||
}
|
||||
|
||||
export function expandProperty(query: StructureQuery, property: QueryFn): StructureQuery {
|
||||
return ctx => {
|
||||
return function query_expandProperty(ctx) {
|
||||
const src = query(ctx);
|
||||
const propertyToStructureIndexMap = new Map<any, UniqueArray<number>>();
|
||||
|
||||
@@ -305,44 +304,44 @@ export interface IncludeConnectedParams {
|
||||
}
|
||||
|
||||
export function includeConnected({ query, layerCount, wholeResidues, linkTest }: IncludeConnectedParams): StructureQuery {
|
||||
const bt = linkTest || defaultLinkTest;
|
||||
const lc = Math.max(layerCount, 0);
|
||||
return ctx => {
|
||||
return function query_includeConnected(ctx) {
|
||||
const builder = StructureSelection.UniqueBuilder(ctx.inputStructure);
|
||||
const src = query(ctx);
|
||||
ctx.pushCurrentLink();
|
||||
ctx.atomicLink.setTestFn(linkTest);
|
||||
StructureSelection.forEach(src, (s, sI) => {
|
||||
let incl = s;
|
||||
for (let i = 0; i < lc; i++) {
|
||||
incl = includeConnectedStep(ctx, bt, wholeResidues, incl);
|
||||
incl = includeConnectedStep(ctx, wholeResidues, incl);
|
||||
}
|
||||
builder.add(incl);
|
||||
if (sI % 10 === 0) ctx.throwIfTimedOut();
|
||||
});
|
||||
ctx.popCurrentLink();
|
||||
|
||||
return builder.getSelection();
|
||||
}
|
||||
}
|
||||
|
||||
function includeConnectedStep(ctx: QueryContext, linkTest: QueryFn<boolean>, wholeResidues: boolean, structure: Structure) {
|
||||
const expanded = expandConnected(ctx, structure, linkTest);
|
||||
function includeConnectedStep(ctx: QueryContext, wholeResidues: boolean, structure: Structure) {
|
||||
const expanded = expandConnected(ctx, structure);
|
||||
if (wholeResidues) return getWholeResidues(ctx, ctx.inputStructure, expanded);
|
||||
return expanded;
|
||||
}
|
||||
|
||||
function expandConnected(ctx: QueryContext, structure: Structure, linkTest: QueryFn<boolean>) {
|
||||
function expandConnected(ctx: QueryContext, structure: Structure) {
|
||||
const inputStructure = ctx.inputStructure;
|
||||
const interLinks = inputStructure.links;
|
||||
const builder = new StructureUniqueSubsetBuilder(inputStructure);
|
||||
|
||||
const processedUnits = new Set<number>();
|
||||
// Note: each link is visited twice so that link.atom-a and link.atom-b both get the "swapped values"
|
||||
const visitedSourceUnits = new Set<number>();
|
||||
|
||||
const atomicLink = ctx.atomicLink;
|
||||
|
||||
// Process intra unit links
|
||||
for (const unit of structure.units) {
|
||||
processedUnits.add(unit.id);
|
||||
|
||||
if (unit.kind !== Unit.Kind.Atomic) {
|
||||
// add the whole unit
|
||||
builder.beginUnit(unit.id);
|
||||
@@ -353,50 +352,71 @@ function expandConnected(ctx: QueryContext, structure: Structure, linkTest: Quer
|
||||
continue;
|
||||
}
|
||||
|
||||
const inputUnit = inputStructure.unitMap.get(unit.id) as Unit.Atomic;
|
||||
const { offset: intraLinkOffset, b: intraLinkB, edgeProps: { flags, order } } = inputUnit.links;
|
||||
const inputUnitA = inputStructure.unitMap.get(unit.id) as Unit.Atomic;
|
||||
const { offset: intraLinkOffset, b: intraLinkB, edgeProps: { flags, order } } = inputUnitA.links;
|
||||
|
||||
// Process intra unit links
|
||||
atomicLink.link.aUnit = inputUnit;
|
||||
atomicLink.link.bUnit = inputUnit;
|
||||
atomicLink.a.unit = inputUnitA;
|
||||
atomicLink.b.unit = inputUnitA;
|
||||
for (let i = 0, _i = unit.elements.length; i < _i; i++) {
|
||||
// add the current element
|
||||
builder.addToUnit(unit.id, unit.elements[i]);
|
||||
|
||||
const srcIndex = SortedArray.indexOf(inputUnit.elements, unit.elements[i]);
|
||||
atomicLink.link.aIndex = srcIndex as StructureElement.UnitIndex;
|
||||
const aIndex = SortedArray.indexOf(inputUnitA.elements, unit.elements[i]) as StructureElement.UnitIndex;
|
||||
|
||||
// check intra unit links
|
||||
for (let lI = intraLinkOffset[srcIndex], _lI = intraLinkOffset[srcIndex + 1]; lI < _lI; lI++) {
|
||||
atomicLink.link.bIndex = intraLinkB[lI] as StructureElement.UnitIndex;
|
||||
for (let lI = intraLinkOffset[aIndex], _lI = intraLinkOffset[aIndex + 1]; lI < _lI; lI++) {
|
||||
const bIndex = intraLinkB[lI] as StructureElement.UnitIndex;
|
||||
const bElement = inputUnitA.elements[bIndex];
|
||||
|
||||
// Check if the element is already present:
|
||||
if (SortedArray.has(unit.elements, bElement) || builder.has(unit.id, bElement)) continue;
|
||||
|
||||
atomicLink.aIndex = aIndex;
|
||||
atomicLink.a.element = unit.elements[i];
|
||||
atomicLink.bIndex = bIndex;
|
||||
atomicLink.b.element = bElement;
|
||||
atomicLink.type = flags[lI];
|
||||
atomicLink.order = order[lI];
|
||||
if (linkTest(ctx)) {
|
||||
builder.addToUnit(unit.id, inputUnit.elements[intraLinkB[lI]]);
|
||||
|
||||
if (atomicLink.test(ctx, true)) {
|
||||
builder.addToUnit(unit.id, bElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process inter unit links
|
||||
for (const linkedUnit of interLinks.getLinkedUnits(inputUnit)) {
|
||||
if (processedUnits.has(linkedUnit.unitB.id)) continue;
|
||||
for (const linkedUnit of interLinks.getLinkedUnits(inputUnitA)) {
|
||||
if (visitedSourceUnits.has(linkedUnit.unitB.id)) continue;
|
||||
const currentUnitB = structure.unitMap.get(linkedUnit.unitB.id);
|
||||
|
||||
atomicLink.link.bUnit = linkedUnit.unitB;
|
||||
for (const aI of linkedUnit.linkedElementIndices) {
|
||||
// check if the element is in the expanded structure
|
||||
if (!SortedArray.has(unit.elements, inputUnit.elements[aI])) continue;
|
||||
if (!SortedArray.has(unit.elements, inputUnitA.elements[aI])) continue;
|
||||
|
||||
atomicLink.link.aIndex = aI;
|
||||
for (const bond of linkedUnit.getBonds(aI)) {
|
||||
atomicLink.link.bIndex = bond.indexB;
|
||||
const bElement = linkedUnit.unitB.elements[bond.indexB];
|
||||
|
||||
// Check if the element is already present:
|
||||
if ((currentUnitB && SortedArray.has(currentUnitB.elements, bElement)) || builder.has(linkedUnit.unitB.id, bElement)) continue;
|
||||
|
||||
atomicLink.a.unit = inputUnitA;
|
||||
atomicLink.aIndex = aI;
|
||||
atomicLink.a.element = inputUnitA.elements[aI];
|
||||
atomicLink.b.unit = linkedUnit.unitB;
|
||||
atomicLink.bIndex = bond.indexB;
|
||||
atomicLink.b.element = bElement;
|
||||
atomicLink.type = bond.flag;
|
||||
atomicLink.order = bond.order;
|
||||
if (linkTest(ctx)) {
|
||||
builder.addToUnit(linkedUnit.unitB.id, linkedUnit.unitB.elements[bond.indexB]);
|
||||
|
||||
if (atomicLink.test(ctx, true)) {
|
||||
builder.addToUnit(linkedUnit.unitB.id, bElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitedSourceUnits.add(inputUnitA.id);
|
||||
}
|
||||
|
||||
return builder.getStructure();
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
import { Structure } from '../structure'
|
||||
import { StructureSelection } from './selection'
|
||||
import { QueryContext, QueryFn } from './context';
|
||||
import { QueryContext, QueryFn, QueryContextOptions } from './context';
|
||||
|
||||
interface StructureQuery extends QueryFn<StructureSelection> { }
|
||||
namespace StructureQuery {
|
||||
export function run(query: StructureQuery, structure: Structure, timeoutMs = 0) {
|
||||
return query(new QueryContext(structure, timeoutMs));
|
||||
export function run(query: StructureQuery, structure: Structure, options?: QueryContextOptions) {
|
||||
return query(new QueryContext(structure, options));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace StructureSelection {
|
||||
return structureUnion(sel.source, sel.structures);
|
||||
}
|
||||
|
||||
export function toLoci(sel: StructureSelection): StructureElement.Loci {
|
||||
/** Convert selection to loci and use "current structure units" in Loci elements */
|
||||
export function toLociWithCurrentUnits(sel: StructureSelection): StructureElement.Loci {
|
||||
const elements: { unit: Unit, indices: OrderedSet<StructureElement.UnitIndex> }[] = [];
|
||||
const { unitMap } = sel.source;
|
||||
|
||||
@@ -57,7 +58,7 @@ namespace StructureSelection {
|
||||
}
|
||||
|
||||
/** use source unit in loci.elements */
|
||||
export function toLoci2(sel: StructureSelection): StructureElement.Loci {
|
||||
export function toLociWithSourceUnits(sel: StructureSelection): StructureElement.Loci {
|
||||
const elements: { unit: Unit, indices: OrderedSet<StructureElement.UnitIndex> }[] = [];
|
||||
const { unitMap } = sel.source;
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace AccessibleSurfaceArea {
|
||||
|
||||
if (isNucleic(residueType)) {
|
||||
ctx.atomRadius[aI] = determineRadiusNucl(atomId, element, compId);
|
||||
} else if (residueType === MoleculeType.protein) {
|
||||
} else if (residueType === MoleculeType.Protein) {
|
||||
ctx.atomRadius[aI] = determineRadiusAmino(atomId, element, compId);
|
||||
} else {
|
||||
ctx.atomRadius[aI] = handleNonStandardCase(element);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Segmentation, SortedArray } from '../../../../mol-data/int';
|
||||
import { combinations } from '../../../../mol-data/util/combination';
|
||||
import { IntAdjacencyGraph } from '../../../../mol-math/graph';
|
||||
import { Vec3 } from '../../../../mol-math/linear-algebra';
|
||||
import PrincipalAxes from '../../../../mol-math/linear-algebra/matrix/principal-axes';
|
||||
import { PrincipalAxes } from '../../../../mol-math/linear-algebra/matrix/principal-axes';
|
||||
import { fillSerial } from '../../../../mol-util/array';
|
||||
import { ResidueIndex, Model } from '../../model';
|
||||
import { ElementSymbol } from '../../model/types';
|
||||
@@ -195,7 +195,7 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
|
||||
const ringAtoms = rings.all[sugarRings[j]];
|
||||
const anomericCarbon = getAnomericCarbon(unit, ringAtoms)
|
||||
|
||||
const pa = new PrincipalAxes(getPositionMatrix(unit, ringAtoms))
|
||||
const pa = PrincipalAxes.ofPoints(getPositionMatrix(unit, ringAtoms))
|
||||
const center = Vec3.copy(Vec3.zero(), pa.center)
|
||||
const normal = Vec3.copy(Vec3.zero(), pa.normVecC)
|
||||
const direction = getDirection(Vec3.zero(), unit, anomericCarbon, center)
|
||||
|
||||
@@ -211,26 +211,26 @@ export const MonosaccharidesColorTable: [string, Color][] = [
|
||||
const CommonSaccharideNames: { [k: string]: string[] } = {
|
||||
// Hexose
|
||||
Glc: [
|
||||
'GLC', 'BGC',
|
||||
'GLC', 'BGC', 'Z8T',
|
||||
'TRE', // di-saccharide but homomer
|
||||
'MLR', // tri-saccharide but homomer
|
||||
],
|
||||
Man: ['MAN', 'BMA'],
|
||||
Gal: ['GLA', 'GAL', 'GZL'],
|
||||
Gul: ['4GL', 'GL0'],
|
||||
Alt: ['Z6H', '3MK'],
|
||||
All: ['AFD', 'ALL'],
|
||||
Tal: [],
|
||||
Ido: ['Z0F', '4N2'],
|
||||
Gal: ['GLA', 'GAL', 'GZL', 'GXL', 'GIV'],
|
||||
Gul: ['4GL', 'GL0', 'GUP', 'Z8H'],
|
||||
Alt: ['Z6H', '3MK', 'SHD'],
|
||||
All: ['AFD', 'ALL', 'WOO', 'Z2D'],
|
||||
Tal: ['ZEE', 'A5C'],
|
||||
Ido: ['ZCD', 'Z0F', '4N2'],
|
||||
// HexNAc
|
||||
GlcNAc: ['NDG', 'NAG'],
|
||||
GlcNAc: ['NDG', 'NAG', 'NGZ'],
|
||||
ManNAc: ['BM3', 'BM7'],
|
||||
GalNAc: ['A2G', 'NGA'],
|
||||
GalNAc: ['A2G', 'NGA', 'YYQ'],
|
||||
GulNAc: ['LXB'],
|
||||
AltNAc: [],
|
||||
AllNAc: ['NAA'],
|
||||
TalNAc: [],
|
||||
IdoNAc: [],
|
||||
IdoNAc: ['LXZ'],
|
||||
// Hexosamine
|
||||
GlcN: ['PA1', 'GCS'],
|
||||
ManN: ['95Z'],
|
||||
@@ -244,24 +244,24 @@ const CommonSaccharideNames: { [k: string]: string[] } = {
|
||||
GlcA: ['GCU', 'BDP'],
|
||||
ManA: ['MAV', 'BEM'],
|
||||
GalA: ['ADA', 'GTR', 'GTK'],
|
||||
GulA: [],
|
||||
GulA: ['LGU'],
|
||||
AltA: [],
|
||||
AllA: [],
|
||||
TalA: ['X1X', 'X0X'],
|
||||
IdoA: ['IDR'],
|
||||
// Deoxyhexose
|
||||
Qui: ['G6D', 'YYK'],
|
||||
Rha: ['RAM', 'RM4'],
|
||||
Rha: ['RAM', 'RM4', 'XXR'],
|
||||
'6dGul': ['66O'],
|
||||
'6dAlt': [],
|
||||
'6dTal': [],
|
||||
Fuc: ['FUC', 'FUL'],
|
||||
Fuc: ['FUC', 'FUL', 'FCA', 'FCB'],
|
||||
// DeoxyhexNAc
|
||||
QuiNAc: ['Z9W'],
|
||||
RhaNAc: [],
|
||||
'6dAltNAc': [],
|
||||
'6dTalNAc': [],
|
||||
FucNAc: [],
|
||||
FucNAc: ['49T'],
|
||||
// Di-deoxyhexose
|
||||
Oli: ['DDA', 'RAE', 'Z5J'],
|
||||
Tyv: ['TYV'],
|
||||
@@ -270,10 +270,10 @@ const CommonSaccharideNames: { [k: string]: string[] } = {
|
||||
Dig: ['Z3U'],
|
||||
Col: [],
|
||||
// Pentose
|
||||
Ara: ['ARA', 'ARB', 'AHR', 'FUB'],
|
||||
Ara: ['64K', 'ARA', 'ARB', 'AHR', 'FUB', 'BXY', 'BXX'],
|
||||
Lyx: ['LDY', 'Z4W'],
|
||||
Xyl: ['XZS', 'XYP', 'XYZ'],
|
||||
Rib: ['YYM', 'RIP', 'RIB', 'BDR'],
|
||||
Xyl: ['XYS', 'XYP', 'XYZ', 'HSY', 'LXC'],
|
||||
Rib: ['YYM', 'RIP', 'RIB', 'BDR', '0MK', 'Z6J', '32O'],
|
||||
// Deoxynonulosonate
|
||||
Kdn: ['KDM', 'KDN'],
|
||||
Neu5Ac: ['SIA', 'SLB'],
|
||||
@@ -296,10 +296,10 @@ const CommonSaccharideNames: { [k: string]: string[] } = {
|
||||
Mur: ['1S4', 'MUR'],
|
||||
// Assigned
|
||||
Api: ['XXM'],
|
||||
Fru: ['BDF', 'Z9N', 'FRU'],
|
||||
Fru: ['BDF', 'Z9N', 'FRU', 'LFR'],
|
||||
Tag: ['T6T'],
|
||||
Sor: ['SOE'],
|
||||
Psi: ['PSV'],
|
||||
Psi: ['PSV', 'SF6', 'SF9'],
|
||||
}
|
||||
|
||||
const UnknownSaccharideNames = [
|
||||
|
||||
@@ -12,8 +12,10 @@ import { hashFnv32a, hash2 } from '../../../../mol-data/util';
|
||||
import SortedRanges from '../../../../mol-data/int/sorted-ranges';
|
||||
import { UnitIndex } from './element';
|
||||
import { Loci } from './loci';
|
||||
import Expression from '../../../../mol-script/language/expression';
|
||||
import { MolScriptBuilder as MS } from '../../../../mol-script/language/builder';
|
||||
|
||||
interface BundleElement {
|
||||
export interface BundleElement {
|
||||
/**
|
||||
* Array (sorted by first element in sub-array) of
|
||||
* arrays of `Unit.id`s that share the same `Unit.invariantId`
|
||||
@@ -165,23 +167,39 @@ export namespace Bundle {
|
||||
const _units = getUnitsFromIds(g, parent)
|
||||
if (_units.length === 0) continue
|
||||
|
||||
const unit = _units[0] // the elements are grouped by unit.invariantId
|
||||
const ue = _units[0].elements // the elements are grouped by unit.invariantId
|
||||
const rangesSize = SortedRanges.size(e.ranges)
|
||||
const _indices = new Int32Array(e.set.length + rangesSize)
|
||||
const setSize = e.set.length
|
||||
const _indices = new Int32Array(setSize + rangesSize)
|
||||
let indices: SortedArray<ElementIndex>
|
||||
if (e.ranges.length === 0) {
|
||||
for (let i = 0, il = e.set.length; i < il; ++i) {
|
||||
_indices[i] = unit.elements[e.set[i]]
|
||||
if (rangesSize === 0) {
|
||||
for (let i = 0, il = setSize; i < il; ++i) {
|
||||
_indices[i] = ue[e.set[i]]
|
||||
}
|
||||
indices = SortedArray.ofSortedArray(_indices)
|
||||
} else if (e.set.length === 0) {
|
||||
SortedRanges.forEach(e.ranges, (v, i) => _indices[i] = unit.elements[v])
|
||||
} else if (setSize === 0) {
|
||||
SortedRanges.forEach(e.ranges, (v, i) => _indices[i] = ue[v])
|
||||
indices = SortedArray.ofSortedArray(_indices)
|
||||
} else {
|
||||
const rangesSize = SortedRanges.size(e.ranges)
|
||||
SortedRanges.forEach(e.ranges, (v, i) => _indices[i] = unit.elements[v])
|
||||
SortedRanges.forEach(e.set, (v, i) => _indices[i + rangesSize] = unit.elements[v])
|
||||
indices = SortedArray.ofUnsortedArray(_indices) // requires sort
|
||||
if (SortedArray.min(e.set) > SortedRanges.max(e.ranges)) {
|
||||
SortedRanges.forEach(e.ranges, (v, i) => _indices[i] = ue[v])
|
||||
for (let i = 0, il = setSize; i < il; ++i) {
|
||||
_indices[i + rangesSize] = ue[e.set[i]]
|
||||
}
|
||||
indices = SortedArray.ofSortedArray(_indices)
|
||||
} else if (SortedRanges.min(e.ranges) > SortedArray.max(e.set)) {
|
||||
for (let i = 0, il = setSize; i < il; ++i) {
|
||||
_indices[i] = ue[e.set[i]]
|
||||
}
|
||||
SortedRanges.forEach(e.ranges, (v, i) => _indices[i + setSize] = ue[v])
|
||||
indices = SortedArray.ofSortedArray(_indices)
|
||||
} else {
|
||||
SortedRanges.forEach(e.ranges, (v, i) => _indices[i] = ue[v])
|
||||
for (let i = 0, il = setSize; i < il; ++i) {
|
||||
_indices[i + rangesSize] = ue[e.set[i]]
|
||||
}
|
||||
indices = SortedArray.ofUnsortedArray(_indices) // requires sort
|
||||
}
|
||||
}
|
||||
|
||||
for (const unit of _units) {
|
||||
@@ -192,6 +210,21 @@ export namespace Bundle {
|
||||
return Structure.create(units, { parent })
|
||||
}
|
||||
|
||||
|
||||
function elementToExpression(e: BundleElement): Expression {
|
||||
return MS.internal.generator.bundleElement({
|
||||
groupedUnits: MS.core.type.list(e.groupedUnits.map(u => MS.core.type.list(u))),
|
||||
ranges: MS.core.type.list(e.ranges),
|
||||
set: MS.core.type.list(e.set),
|
||||
})
|
||||
}
|
||||
|
||||
export function toExpression(bundle: Bundle): Expression {
|
||||
return MS.internal.generator.bundle({
|
||||
elements: MS.core.type.list(bundle.elements.map(elementToExpression))
|
||||
});
|
||||
}
|
||||
|
||||
export function areEqual(a: Bundle, b: Bundle) {
|
||||
if (a.elements.length !== b.elements.length) return false
|
||||
for (let i = 0, il = a.elements.length; i < il; ++i) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import { ElementIndex } from '../../model';
|
||||
import Unit from '../unit';
|
||||
import { Vec3 } from '../../../../mol-math/linear-algebra';
|
||||
|
||||
export { Location }
|
||||
|
||||
@@ -18,7 +19,7 @@ interface Location<U = Unit> {
|
||||
}
|
||||
|
||||
namespace Location {
|
||||
export function create(unit?: Unit, element?: ElementIndex): Location {
|
||||
export function create<U extends Unit>(unit?: U, element?: ElementIndex): Location<U> {
|
||||
return { kind: 'element-location', unit: unit!, element: element || (0 as ElementIndex) };
|
||||
}
|
||||
|
||||
@@ -37,4 +38,11 @@ namespace Location {
|
||||
export function is(x: any): x is Location {
|
||||
return !!x && x.kind === 'element-location';
|
||||
}
|
||||
|
||||
const pA = Vec3.zero(), pB = Vec3.zero();
|
||||
export function distance(a: Location, b: Location) {
|
||||
a.unit.conformation.position(a.element, pA);
|
||||
b.unit.conformation.position(b.element, pB);
|
||||
return Vec3.distance(pA, pB);
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,13 @@ import { sortArray, hashFnv32a, hash2 } from '../../../../mol-data/util';
|
||||
import Expression from '../../../../mol-script/language/expression';
|
||||
import { ElementIndex } from '../../model';
|
||||
import { UnitIndex } from './element';
|
||||
import { Location } from './location';
|
||||
import { ChainIndex } from '../../model/indexing';
|
||||
import { PrincipalAxes } from '../../../../mol-math/linear-algebra/matrix/principal-axes';
|
||||
import Matrix from '../../../../mol-math/linear-algebra/matrix/matrix';
|
||||
import { NumberArray } from '../../../../mol-util/type-helpers';
|
||||
|
||||
/** Represents multiple element index locations */
|
||||
/** Represents multiple structure element index locations */
|
||||
export interface Loci {
|
||||
readonly kind: 'element-loci',
|
||||
readonly structure: Structure,
|
||||
@@ -78,6 +83,29 @@ export namespace Loci {
|
||||
return Loci(structure, []);
|
||||
}
|
||||
|
||||
export function getFirstLocation(loci: Loci, e?: Location): Location | undefined {
|
||||
if (isEmpty(loci)) return void 0;
|
||||
const unit = loci.elements[0].unit;
|
||||
const element = unit.elements[OrderedSet.getAt(loci.elements[0].indices, 0)];
|
||||
if (e) {
|
||||
e.unit = loci.elements[0].unit;
|
||||
e.element = element;
|
||||
return e;
|
||||
}
|
||||
return Location.create(unit, element);
|
||||
}
|
||||
|
||||
export function toStructure(loci: Loci): Structure {
|
||||
const units: Unit[] = []
|
||||
for (const e of loci.elements) {
|
||||
const { unit, indices } = e
|
||||
const elements = new Int32Array(OrderedSet.size(indices))
|
||||
OrderedSet.forEach(indices, (v, i) => elements[i] = unit.elements[v])
|
||||
units.push(unit.getChild(SortedArray.ofSortedArray(elements)))
|
||||
}
|
||||
return Structure.create(units, { parent: loci.structure.parent })
|
||||
}
|
||||
|
||||
export function remap(loci: Loci, structure: Structure): Loci {
|
||||
if (structure === loci.structure) return loci
|
||||
|
||||
@@ -176,13 +204,38 @@ export namespace Loci {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function extendToWholeResidues(loci: Loci): Loci {
|
||||
/** Check if second loci is a subset of the first */
|
||||
export function isSubset(xs: Loci, ys: Loci): boolean {
|
||||
if (Loci.isEmpty(xs)) return Loci.isEmpty(ys);
|
||||
|
||||
const map = new Map<number, OrderedSet<UnitIndex>>();
|
||||
|
||||
for (const e of xs.elements) map.set(e.unit.id, e.indices);
|
||||
|
||||
let isSubset = false;
|
||||
for (const e of ys.elements) {
|
||||
if (!map.has(e.unit.id)) continue;
|
||||
if (!OrderedSet.isSubset(map.get(e.unit.id)!, e.indices)) return false;
|
||||
else isSubset = true;
|
||||
}
|
||||
|
||||
return isSubset;
|
||||
}
|
||||
|
||||
export function extendToWholeResidues(loci: Loci, restrictToConformation?: boolean): Loci {
|
||||
const elements: Loci['elements'][0][] = [];
|
||||
const residueAltIds = new Set<string>()
|
||||
|
||||
for (const lociElement of loci.elements) {
|
||||
if (isWholeUnit(lociElement)) {
|
||||
elements[elements.length] = lociElement;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lociElement.unit.kind === Unit.Kind.Atomic) {
|
||||
const unitElements = lociElement.unit.elements;
|
||||
const h = lociElement.unit.model.atomicHierarchy;
|
||||
const { label_alt_id } = lociElement.unit.model.atomicHierarchy.atoms;
|
||||
|
||||
const { index: residueIndex, offsets: residueOffsets } = h.residueAtomSegments;
|
||||
|
||||
@@ -190,15 +243,26 @@ export namespace Loci {
|
||||
const indices = lociElement.indices, len = OrderedSet.size(indices);
|
||||
let i = 0;
|
||||
while (i < len) {
|
||||
const rI = residueIndex[unitElements[OrderedSet.getAt(indices, i)]];
|
||||
residueAltIds.clear()
|
||||
const eI = unitElements[OrderedSet.getAt(indices, i)]
|
||||
const rI = residueIndex[eI];
|
||||
residueAltIds.add(label_alt_id.value(eI))
|
||||
i++;
|
||||
while (i < len && residueIndex[unitElements[OrderedSet.getAt(indices, i)]] === rI) {
|
||||
while (i < len) {
|
||||
const eI = unitElements[OrderedSet.getAt(indices, i)]
|
||||
if (residueIndex[eI] !== rI) break;
|
||||
residueAltIds.add(label_alt_id.value(eI))
|
||||
i++;
|
||||
}
|
||||
|
||||
const hasSharedAltId = residueAltIds.has('')
|
||||
for (let j = residueOffsets[rI], _j = residueOffsets[rI + 1]; j < _j; j++) {
|
||||
const idx = OrderedSet.indexOf(unitElements, j);
|
||||
if (idx >= 0) newIndices[newIndices.length] = idx as UnitIndex;
|
||||
if (idx >= 0) {
|
||||
const altId = label_alt_id.value(j)
|
||||
if (!restrictToConformation || hasSharedAltId || !altId || residueAltIds.has(altId)) {
|
||||
newIndices[newIndices.length] = idx as UnitIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,44 +284,103 @@ export namespace Loci {
|
||||
}
|
||||
}
|
||||
|
||||
function isWholeUnit(element: Loci['elements'][0]) {
|
||||
return element.unit.elements.length === OrderedSet.size(element.indices);
|
||||
}
|
||||
|
||||
function makeIndexSet(newIndices: number[]): OrderedSet<UnitIndex> {
|
||||
if (newIndices.length > 12 && newIndices[newIndices.length - 1] - newIndices[0] === newIndices.length - 1) {
|
||||
return Interval.ofRange(newIndices[0], newIndices[newIndices.length - 1])
|
||||
} else {
|
||||
return SortedArray.ofSortedArray(newIndices)
|
||||
}
|
||||
}
|
||||
|
||||
function collectChains(unit: Unit, chainIndices: Set<ChainIndex>, elements: Loci['elements'][0][]) {
|
||||
const { index } = getChainSegments(unit);
|
||||
const xs = unit.elements;
|
||||
let size = 0;
|
||||
for (let i = 0 as UnitIndex, _i = xs.length; i < _i; i++) {
|
||||
const eI = xs[i];
|
||||
const cI = index[eI];
|
||||
if (!chainIndices.has(cI)) continue;
|
||||
size++;
|
||||
}
|
||||
|
||||
if (size === unit.elements.length) {
|
||||
elements[elements.length] = { unit, indices: Interval.ofBounds(0, size) };
|
||||
return;
|
||||
}
|
||||
|
||||
const newIndices = new Int32Array(size) as any as UnitIndex[];
|
||||
size = 0;
|
||||
for (let i = 0 as UnitIndex, _i = xs.length; i < _i; i++) {
|
||||
const eI = xs[i];
|
||||
const cI = index[eI];
|
||||
if (!chainIndices.has(cI)) continue;
|
||||
newIndices[size++] = i;
|
||||
}
|
||||
|
||||
if (newIndices.length > 0) {
|
||||
elements[elements.length] = { unit, indices: makeIndexSet(newIndices) };
|
||||
}
|
||||
}
|
||||
|
||||
function extendGroupToWholeChains(loci: Loci, start: number, end: number, isPartitioned: boolean, elements: Loci['elements'][0][]) {
|
||||
const { index: chainIndex } = getChainSegments(loci.elements[0].unit);
|
||||
|
||||
const chainIndices = new Set<ChainIndex>();
|
||||
|
||||
for (let lI = start; lI < end; lI++) {
|
||||
const lociElement = loci.elements[lI];
|
||||
const indices = lociElement.indices;
|
||||
const unitElements = lociElement.unit.elements;
|
||||
for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
|
||||
chainIndices.add(chainIndex[unitElements[OrderedSet.getAt(indices, i)]]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPartitioned) {
|
||||
const baseUnit = loci.elements[0].unit;
|
||||
// TODO: check for accidental quadratic for really large structures (but should be ok).
|
||||
for (const unit of loci.structure.units) {
|
||||
if (!Unit.areSameChainOperatorGroup(unit, baseUnit)) continue;
|
||||
collectChains(unit, chainIndices, elements);
|
||||
}
|
||||
} else {
|
||||
for (let lI = start; lI < end; lI++) {
|
||||
collectChains(loci.elements[lI].unit, chainIndices, elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function extendToWholeChains(loci: Loci): Loci {
|
||||
const elements: Loci['elements'][0][] = [];
|
||||
|
||||
for (const lociElement of loci.elements) {
|
||||
const _newIndices: UnitIndex[] = [];
|
||||
const unitElements = lociElement.unit.elements;
|
||||
|
||||
const { index: chainIndex, offsets: chainOffsets } = getChainSegments(lociElement.unit)
|
||||
|
||||
const indices = lociElement.indices, len = OrderedSet.size(indices);
|
||||
let i = 0;
|
||||
while (i < len) {
|
||||
const cI = chainIndex[unitElements[OrderedSet.getAt(indices, i)]];
|
||||
i++;
|
||||
while (i < len && chainIndex[unitElements[OrderedSet.getAt(indices, i)]] === cI) {
|
||||
for (let i = 0, len = loci.elements.length; i < len; i++) {
|
||||
const e = loci.elements[i];
|
||||
if (Unit.Traits.is(e.unit.traits, Unit.Trait.Patitioned)) {
|
||||
const start = i;
|
||||
while (i < len && Unit.areSameChainOperatorGroup(loci.elements[i].unit, e.unit)) {
|
||||
i++;
|
||||
}
|
||||
|
||||
for (let j = chainOffsets[cI], _j = chainOffsets[cI + 1]; j < _j; j++) {
|
||||
const idx = OrderedSet.indexOf(unitElements, j);
|
||||
if (idx >= 0) _newIndices[_newIndices.length] = idx as UnitIndex;
|
||||
const end = i;
|
||||
i--;
|
||||
extendGroupToWholeChains(loci, start, end, true, elements);
|
||||
} else {
|
||||
if (isWholeUnit(e)) {
|
||||
elements[elements.length] = e;
|
||||
} else {
|
||||
extendGroupToWholeChains(loci, i, i + 1, false, elements);
|
||||
}
|
||||
}
|
||||
|
||||
let newIndices: OrderedSet<UnitIndex>
|
||||
if (_newIndices.length > 12 && _newIndices[_newIndices.length - 1] - _newIndices[0] === _newIndices.length - 1) {
|
||||
newIndices = Interval.ofRange(_newIndices[0], _newIndices[_newIndices.length - 1])
|
||||
} else {
|
||||
newIndices = SortedArray.ofSortedArray(_newIndices)
|
||||
}
|
||||
|
||||
elements[elements.length] = { unit: lociElement.unit, indices: newIndices };
|
||||
}
|
||||
|
||||
return Loci(loci.structure, elements);
|
||||
}
|
||||
|
||||
const boundaryHelper = new BoundaryHelper(), tempPos = Vec3.zero();
|
||||
const boundaryHelper = new BoundaryHelper();
|
||||
const tempPosBoundary = Vec3.zero();
|
||||
export function getBoundary(loci: Loci): Boundary {
|
||||
boundaryHelper.reset(0);
|
||||
|
||||
@@ -267,8 +390,8 @@ export namespace Loci {
|
||||
const { elements } = e.unit;
|
||||
for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
|
||||
const eI = elements[OrderedSet.getAt(indices, i)];
|
||||
pos(eI, tempPos);
|
||||
boundaryHelper.boundaryStep(tempPos, r(eI));
|
||||
pos(eI, tempPosBoundary);
|
||||
boundaryHelper.boundaryStep(tempPosBoundary, r(eI));
|
||||
}
|
||||
}
|
||||
boundaryHelper.finishBoundaryStep();
|
||||
@@ -278,14 +401,38 @@ export namespace Loci {
|
||||
const { elements } = e.unit;
|
||||
for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
|
||||
const eI = elements[OrderedSet.getAt(indices, i)];
|
||||
pos(eI, tempPos);
|
||||
boundaryHelper.extendStep(tempPos, r(eI));
|
||||
pos(eI, tempPosBoundary);
|
||||
boundaryHelper.extendStep(tempPosBoundary, r(eI));
|
||||
}
|
||||
}
|
||||
|
||||
return { box: boundaryHelper.getBox(), sphere: boundaryHelper.getSphere() };
|
||||
}
|
||||
|
||||
const tempPos = Vec3.zero();
|
||||
export function toPositionsArray(loci: Loci, positions: NumberArray, offset = 0) {
|
||||
let m = offset
|
||||
for (const e of loci.elements) {
|
||||
const { indices } = e
|
||||
const pos = e.unit.conformation.position
|
||||
const { elements } = e.unit
|
||||
const indexCount = OrderedSet.size(indices)
|
||||
for (let i = 0; i < indexCount; i++) {
|
||||
const eI = elements[OrderedSet.getAt(indices, i)]
|
||||
pos(eI, tempPos)
|
||||
Vec3.toArray(tempPos, positions, m + i * 3)
|
||||
}
|
||||
m += indexCount * 3
|
||||
}
|
||||
return positions
|
||||
}
|
||||
|
||||
export function getPrincipalAxes(loci: Loci): PrincipalAxes {
|
||||
const elementCount = size(loci)
|
||||
const positions = toPositionsArray(loci, new Float32Array(3 * elementCount))
|
||||
return PrincipalAxes.ofPoints(Matrix.fromArray(positions, 3, elementCount))
|
||||
}
|
||||
|
||||
function sourceIndex(unit: Unit, element: ElementIndex) {
|
||||
return Unit.isAtomic(unit)
|
||||
? unit.model.atomicHierarchy.atoms.sourceIndex.value(element)
|
||||
|
||||
@@ -2,41 +2,67 @@
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { OrderedSet } from '../../../../mol-data/int';
|
||||
import Unit from '../unit';
|
||||
import { Loci } from './loci';
|
||||
import { Location } from './location';
|
||||
|
||||
import { ChainIndex } from '../../model/indexing';
|
||||
|
||||
export interface Stats {
|
||||
elementCount: number
|
||||
conformationCount: number
|
||||
residueCount: number
|
||||
chainCount: number
|
||||
unitCount: number
|
||||
structureCount: number
|
||||
|
||||
firstElementLoc: Location
|
||||
firstConformationLoc: Location
|
||||
firstResidueLoc: Location
|
||||
firstChainLoc: Location
|
||||
firstUnitLoc: Location
|
||||
firstStructureLoc: Location
|
||||
}
|
||||
|
||||
export namespace Stats {
|
||||
export function create(): Stats {
|
||||
return {
|
||||
elementCount: 0,
|
||||
conformationCount: 0,
|
||||
residueCount: 0,
|
||||
chainCount: 0,
|
||||
unitCount: 0,
|
||||
structureCount: 0,
|
||||
|
||||
firstElementLoc: Location.create(),
|
||||
firstConformationLoc: Location.create(),
|
||||
firstResidueLoc: Location.create(),
|
||||
firstChainLoc: Location.create(),
|
||||
firstUnitLoc: Location.create(),
|
||||
firstStructureLoc: Location.create(),
|
||||
}
|
||||
}
|
||||
|
||||
function addCountHelper<K>(map: Map<K, number>, key: K, inc: number) {
|
||||
const count = map.get(key) || 0
|
||||
map.set(key, count + inc)
|
||||
}
|
||||
|
||||
function handleElement(stats: Stats, element: Loci['elements'][0]) {
|
||||
const { indices, unit } = element
|
||||
const { elements } = unit
|
||||
const size = OrderedSet.size(indices)
|
||||
|
||||
const lociResidueAltIdCounts = new Map<string, number>()
|
||||
const residueAltIdCounts = new Map<string, number>()
|
||||
|
||||
if (size > 0) {
|
||||
Location.set(stats.firstElementLoc, unit, elements[OrderedSet.start(indices)])
|
||||
}
|
||||
|
||||
if (size === 1) {
|
||||
stats.elementCount += 1
|
||||
if (stats.elementCount === 1) {
|
||||
@@ -50,38 +76,58 @@ export namespace Stats {
|
||||
} else {
|
||||
if (Unit.isAtomic(unit)) {
|
||||
const { index, offsets } = unit.model.atomicHierarchy.residueAtomSegments
|
||||
const { label_alt_id } = unit.model.atomicHierarchy.atoms;
|
||||
let i = 0
|
||||
while (i < size) {
|
||||
lociResidueAltIdCounts.clear()
|
||||
let j = 0
|
||||
const eI = elements[OrderedSet.getAt(indices, i)]
|
||||
const rI = index[eI]
|
||||
if (offsets[rI] !== eI) {
|
||||
// partial residue, start missing
|
||||
addCountHelper(lociResidueAltIdCounts, label_alt_id.value(eI), 1)
|
||||
++i
|
||||
++j
|
||||
while (i < size) {
|
||||
const eI = elements[OrderedSet.getAt(indices, i)]
|
||||
if (index[eI] !== rI) break
|
||||
addCountHelper(lociResidueAltIdCounts, label_alt_id.value(eI), 1)
|
||||
++i
|
||||
stats.elementCount += 1
|
||||
while (i < size && index[elements[OrderedSet.getAt(indices, i)]] === rI) {
|
||||
++i
|
||||
stats.elementCount += 1
|
||||
++j
|
||||
}
|
||||
|
||||
if (offsets[rI + 1] - offsets[rI] === j) {
|
||||
// full residue
|
||||
stats.residueCount += 1
|
||||
if (stats.residueCount === 1) {
|
||||
Location.set(stats.firstResidueLoc, unit, offsets[rI])
|
||||
}
|
||||
} else {
|
||||
++i
|
||||
while (i < size && index[elements[OrderedSet.getAt(indices, i)]] === rI) {
|
||||
++i
|
||||
// partial residue
|
||||
residueAltIdCounts.clear()
|
||||
for (let l = offsets[rI], _l = offsets[rI + 1]; l < _l; ++l) {
|
||||
addCountHelper(residueAltIdCounts, label_alt_id.value(l), 1)
|
||||
}
|
||||
|
||||
if (offsets[rI + 1] - 1 === elements[OrderedSet.getAt(indices, i - 1)]) {
|
||||
// full residue
|
||||
stats.residueCount += 1
|
||||
if (stats.residueCount === 1) {
|
||||
Location.set(stats.firstResidueLoc, unit, elements[OrderedSet.start(indices)])
|
||||
}
|
||||
} else {
|
||||
// partial residue, end missing
|
||||
stats.elementCount += offsets[rI + 1] - 1 - elements[OrderedSet.getAt(indices, i - 1)]
|
||||
// check if shared atom count match
|
||||
if (residueAltIdCounts.get('') === lociResidueAltIdCounts.get('')) {
|
||||
lociResidueAltIdCounts.forEach((v, k) => {
|
||||
if (residueAltIdCounts.get(k) !== v) return
|
||||
if (k !== '') {
|
||||
stats.conformationCount += 1
|
||||
if (stats.conformationCount === 1) {
|
||||
for (let l = offsets[rI], _l = offsets[rI + 1]; l < _l; ++l) {
|
||||
if (k === label_alt_id.value(l)) {
|
||||
Location.set(stats.firstConformationLoc, unit, l)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
j -= v
|
||||
})
|
||||
}
|
||||
stats.elementCount += j
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
stats.elementCount += size
|
||||
if (stats.elementCount === 1) {
|
||||
Location.set(stats.firstElementLoc, unit, elements[OrderedSet.start(indices)])
|
||||
@@ -90,14 +136,194 @@ export namespace Stats {
|
||||
}
|
||||
}
|
||||
|
||||
function handleUnitChainsSimple(stats: Stats, element: Loci['elements'][0]) {
|
||||
const { indices, unit } = element;
|
||||
const size = OrderedSet.size(indices);
|
||||
if (size === 0) return;
|
||||
|
||||
const { elements } = unit;
|
||||
|
||||
if (!Unit.Traits.is(unit.traits, Unit.Trait.MultiChain)) {
|
||||
if (size === elements.length) {
|
||||
stats.chainCount += 1;
|
||||
if (stats.chainCount === 1) {
|
||||
Location.set(stats.firstChainLoc, unit, elements[OrderedSet.start(indices)]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const segments = Unit.isAtomic(unit)
|
||||
? unit.model.atomicHierarchy.chainAtomSegments
|
||||
: Unit.isSpheres(unit)
|
||||
? unit.model.coarseHierarchy.spheres.chainElementSegments
|
||||
: Unit.isGaussians(unit)
|
||||
? unit.model.coarseHierarchy.gaussians.chainElementSegments
|
||||
: void 0;
|
||||
|
||||
if (!segments) {
|
||||
console.warn('StructureElement loci stats: unknown unit type');
|
||||
return;
|
||||
}
|
||||
|
||||
const { index, offsets } = segments;
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
let j = 0
|
||||
const eI = elements[OrderedSet.getAt(indices, i)];
|
||||
const cI = index[eI];
|
||||
++i;
|
||||
++j;
|
||||
while (i < size) {
|
||||
const eI = elements[OrderedSet.getAt(indices, i)];
|
||||
if (index[eI] !== cI) break;
|
||||
++i;
|
||||
++j;
|
||||
}
|
||||
|
||||
if (offsets[cI + 1] - offsets[cI] === j) {
|
||||
// full chain
|
||||
stats.chainCount += 1;
|
||||
if (stats.chainCount === 1) {
|
||||
Location.set(stats.firstChainLoc, unit, elements[offsets[cI]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleUnitChainsPartitioned(stats: Stats, lociElements: Loci['elements'], start: number, end: number) {
|
||||
let element = lociElements[start];
|
||||
|
||||
// all the elements have the same model since they are part of the same group so this is ok.
|
||||
const segments = Unit.isAtomic(element.unit)
|
||||
? element.unit.model.atomicHierarchy.chainAtomSegments
|
||||
: Unit.isSpheres(element.unit)
|
||||
? element.unit.model.coarseHierarchy.spheres.chainElementSegments
|
||||
: Unit.isGaussians(element.unit)
|
||||
? element.unit.model.coarseHierarchy.gaussians.chainElementSegments
|
||||
: void 0;
|
||||
|
||||
if (!segments) {
|
||||
console.warn('StructureElement loci stats: unknown unit type');
|
||||
return;
|
||||
}
|
||||
|
||||
const { index, offsets } = segments;
|
||||
|
||||
const chainCounts = new Map<ChainIndex, number>();
|
||||
|
||||
for (let elIndex = start; elIndex < end; elIndex++) {
|
||||
element = lociElements[elIndex];
|
||||
|
||||
const { indices, unit } = element
|
||||
const size = OrderedSet.size(indices);
|
||||
if (size === 0) continue;
|
||||
|
||||
const { elements } = unit;
|
||||
|
||||
if (!Unit.Traits.is(unit.traits, Unit.Trait.MultiChain)) {
|
||||
const eI = elements[OrderedSet.start(indices)];
|
||||
addCountHelper(chainCounts, index[eI], elements.length);
|
||||
continue;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
let j = 0
|
||||
const eI = elements[OrderedSet.getAt(indices, i)];
|
||||
const cI = index[eI];
|
||||
++i;
|
||||
++j;
|
||||
while (i < size) {
|
||||
const eI = elements[OrderedSet.getAt(indices, i)];
|
||||
if (index[eI] !== cI) break;
|
||||
++i;
|
||||
++j;
|
||||
}
|
||||
|
||||
addCountHelper(chainCounts, cI, j);
|
||||
}
|
||||
}
|
||||
|
||||
let firstCI = -1;
|
||||
chainCounts.forEach((count, cI) => {
|
||||
if (offsets[cI + 1] - offsets[cI] === count) {
|
||||
// full chain
|
||||
stats.chainCount += 1;
|
||||
if (stats.chainCount === 1) {
|
||||
firstCI = cI;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (firstCI < 0) return;
|
||||
|
||||
for (let elIndex = start; elIndex < end; elIndex++) {
|
||||
element = lociElements[elIndex];
|
||||
|
||||
const { indices, unit } = element
|
||||
const size = OrderedSet.size(indices);
|
||||
if (size === 0) continue;
|
||||
|
||||
const { elements } = unit;
|
||||
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
const eI = elements[OrderedSet.getAt(indices, i)];
|
||||
const cI = index[eI];
|
||||
if (cI === firstCI) {
|
||||
Location.set(stats.firstChainLoc, unit, eI);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function ofLoci(loci: Loci) {
|
||||
const stats = create()
|
||||
if (!Loci.isEmpty(loci)) {
|
||||
for (const e of loci.elements) handleElement(stats, e)
|
||||
if (Loci.isEmpty(loci)) return stats
|
||||
|
||||
let hasPartitions = false;
|
||||
if (Loci.isWholeStructure(loci)) {
|
||||
stats.structureCount += 1
|
||||
if (stats.structureCount === 1) {
|
||||
const { unit, indices } = loci.elements[0]
|
||||
Location.set(stats.firstStructureLoc, unit, unit.elements[OrderedSet.min(indices)])
|
||||
}
|
||||
} else {
|
||||
for (const e of loci.elements) {
|
||||
handleElement(stats, e)
|
||||
if (!Unit.Traits.is(e.unit.traits, Unit.Trait.Patitioned)) {
|
||||
handleUnitChainsSimple(stats, e);
|
||||
} else {
|
||||
hasPartitions = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPartitions) {
|
||||
for (let i = 0, len = loci.elements.length; i < len; i++) {
|
||||
const e = loci.elements[i];
|
||||
if (!Unit.Traits.is(e.unit.traits, Unit.Trait.Patitioned)) continue;
|
||||
|
||||
const start = i;
|
||||
while (i < len && Unit.areSameChainOperatorGroup(loci.elements[i].unit, e.unit)) {
|
||||
i++;
|
||||
}
|
||||
const end = i;
|
||||
i--;
|
||||
if (end - start === 1) {
|
||||
handleUnitChainsSimple(stats, e);
|
||||
} else {
|
||||
handleUnitChainsPartitioned(stats, loci.elements, start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stats
|
||||
}
|
||||
|
||||
/** Adds counts of two Stats objects together, assumes they describe different structures */
|
||||
export function add(out: Stats, a: Stats, b: Stats) {
|
||||
if (a.elementCount === 1 && b.elementCount === 0) {
|
||||
Location.copy(out.firstElementLoc, a.firstElementLoc)
|
||||
@@ -105,21 +331,42 @@ export namespace Stats {
|
||||
Location.copy(out.firstElementLoc, b.firstElementLoc)
|
||||
}
|
||||
|
||||
if (a.conformationCount === 1 && b.conformationCount === 0) {
|
||||
Location.copy(out.firstConformationLoc, a.firstConformationLoc)
|
||||
} else if (a.conformationCount === 0 && b.conformationCount === 1) {
|
||||
Location.copy(out.firstConformationLoc, b.firstConformationLoc)
|
||||
}
|
||||
|
||||
if (a.residueCount === 1 && b.residueCount === 0) {
|
||||
Location.copy(out.firstResidueLoc, a.firstResidueLoc)
|
||||
} else if (a.residueCount === 0 && b.residueCount === 1) {
|
||||
Location.copy(out.firstResidueLoc, b.firstResidueLoc)
|
||||
}
|
||||
|
||||
if (a.chainCount === 1 && b.chainCount === 0) {
|
||||
Location.copy(out.firstChainLoc, a.firstChainLoc)
|
||||
} else if (a.chainCount === 0 && b.chainCount === 1) {
|
||||
Location.copy(out.firstChainLoc, b.firstChainLoc)
|
||||
}
|
||||
|
||||
if (a.unitCount === 1 && b.unitCount === 0) {
|
||||
Location.copy(out.firstUnitLoc, a.firstUnitLoc)
|
||||
} else if (a.unitCount === 0 && b.unitCount === 1) {
|
||||
Location.copy(out.firstUnitLoc, b.firstUnitLoc)
|
||||
}
|
||||
|
||||
if (a.structureCount === 1 && b.structureCount === 0) {
|
||||
Location.copy(out.firstStructureLoc, a.firstStructureLoc)
|
||||
} else if (a.structureCount === 0 && b.structureCount === 1) {
|
||||
Location.copy(out.firstStructureLoc, b.firstStructureLoc)
|
||||
}
|
||||
|
||||
out.elementCount = a.elementCount + b.elementCount
|
||||
out.conformationCount = a.conformationCount + b.conformationCount
|
||||
out.residueCount = a.residueCount + b.residueCount
|
||||
out.chainCount = a.chainCount + b.chainCount
|
||||
out.unitCount = a.unitCount + b.unitCount
|
||||
out.structureCount = a.structureCount + b.structureCount
|
||||
return out
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,7 @@ const residue = {
|
||||
const id = compId(l)
|
||||
return l.unit.model.properties.modifiedResidues.parentId.get(id) || id
|
||||
}),
|
||||
isNonStandard: p(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.properties.chemicalComponentMap.get(compId(l))!.mon_nstd_flag[0] !== 'y'),
|
||||
hasMicroheterogeneity: p(hasMicroheterogeneity),
|
||||
microheterogeneityCompIds: p(microheterogeneityCompIds),
|
||||
secondary_structure_type: p(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.properties.secondaryStructure.type[l.unit.residueIndex[l.element]]),
|
||||
@@ -163,6 +164,8 @@ const entity = {
|
||||
|
||||
const unit = {
|
||||
id: p(l => l.unit.id),
|
||||
chainGroupId: p(l => l.unit.chainGroupId),
|
||||
multiChain: p(l => Unit.Traits.is(l.unit.traits, Unit.Trait.MultiChain)),
|
||||
object_primitive: p(l => l.unit.objectPrimitive),
|
||||
operator_name: p(l => l.unit.conformation.operator.name),
|
||||
model_index: p(l => l.unit.model.modelNum),
|
||||
|
||||
@@ -277,10 +277,12 @@ class Structure {
|
||||
return this._props.model;
|
||||
}
|
||||
|
||||
/** The master-model, other models can have links to it */
|
||||
get masterModel(): Model | undefined {
|
||||
return this._props.masterModel
|
||||
}
|
||||
|
||||
/** A representative model, e.g. the first model of a trajectory */
|
||||
get representativeModel(): Model | undefined {
|
||||
return this._props.representativeModel
|
||||
}
|
||||
@@ -505,12 +507,12 @@ namespace Structure {
|
||||
return { kind: 'structure-loci', structure };
|
||||
}
|
||||
|
||||
export function toStructureElementLoci(loci: Loci): StructureElement.Loci {
|
||||
export function toStructureElementLoci(structure: Structure): StructureElement.Loci {
|
||||
const elements: StructureElement.Loci['elements'][0][] = []
|
||||
for (const unit of loci.structure.units) {
|
||||
for (const unit of structure.units) {
|
||||
elements.push({ unit, indices: Interval.ofBounds(0, unit.elements.length) })
|
||||
}
|
||||
return StructureElement.Loci(loci.structure, elements);
|
||||
return StructureElement.Loci(structure, elements);
|
||||
}
|
||||
|
||||
export function isLoci(x: any): x is Loci {
|
||||
@@ -525,6 +527,11 @@ namespace Structure {
|
||||
return loci.structure.isEmpty
|
||||
}
|
||||
|
||||
export function remapLoci(loci: Loci, structure: Structure) {
|
||||
if (structure === loci.structure) return loci
|
||||
return Loci(structure)
|
||||
}
|
||||
|
||||
export function create(units: ReadonlyArray<Unit>, props?: Props): Structure {
|
||||
return new Structure(units, props);
|
||||
}
|
||||
@@ -540,7 +547,8 @@ namespace Structure {
|
||||
for (let j = 0, jl = structure.units.length; j < jl; ++j) {
|
||||
const u = structure.units[j]
|
||||
const invariantId = u.invariantId + count
|
||||
const newUnit = Unit.create(units.length, invariantId, u.kind, u.model, u.conformation.operator, u.elements)
|
||||
const chainGroupId = u.chainGroupId + count
|
||||
const newUnit = Unit.create(units.length, invariantId, chainGroupId, u.traits, u.kind, u.model, u.conformation.operator, u.elements)
|
||||
units.push(newUnit)
|
||||
}
|
||||
count = units.length
|
||||
@@ -553,10 +561,12 @@ namespace Structure {
|
||||
* Construct a Structure from a model.
|
||||
*
|
||||
* Generally, a single unit corresponds to a single chain, with the exception
|
||||
* of consecutive "single atom chains" with same entity id.
|
||||
* of consecutive "single atom chains" with same entity_id and same auth_asym_id.
|
||||
*/
|
||||
export function ofModel(model: Model): Structure {
|
||||
const chains = model.atomicHierarchy.chainAtomSegments;
|
||||
const { index } = model.atomicHierarchy
|
||||
const { auth_asym_id } = model.atomicHierarchy.chains
|
||||
const builder = new StructureBuilder({ label: model.label });
|
||||
|
||||
for (let c = 0 as ChainIndex; c < chains.count; c++) {
|
||||
@@ -566,27 +576,34 @@ namespace Structure {
|
||||
// note that it assumes there are no "zero atom residues"
|
||||
let singleAtomResidues = AtomicHierarchy.chainResidueCount(model.atomicHierarchy, c) === chains.offsets[c + 1] - chains.offsets[c]
|
||||
|
||||
// merge all consecutive "single atom chains" with same entity id
|
||||
// merge all consecutive "single atom chains" with same entity_id and same auth_asym_id
|
||||
let multiChain = false
|
||||
while (c + 1 < chains.count
|
||||
&& chains.offsets[c + 1] - chains.offsets[c] === 1
|
||||
&& chains.offsets[c + 2] - chains.offsets[c + 1] === 1
|
||||
) {
|
||||
c++;
|
||||
singleAtomResidues = true
|
||||
const e1 = model.atomicHierarchy.index.getEntityFromChain(c);
|
||||
const e2 = model.atomicHierarchy.index.getEntityFromChain(c + 1 as ChainIndex);
|
||||
const e1 = index.getEntityFromChain(c);
|
||||
const e2 = index.getEntityFromChain(c + 1 as ChainIndex);
|
||||
if (e1 !== e2) break
|
||||
|
||||
const a1 = auth_asym_id.value(c);
|
||||
const a2 = auth_asym_id.value(c + 1);
|
||||
if (a1 !== a2) break
|
||||
|
||||
multiChain = true
|
||||
c++;
|
||||
}
|
||||
|
||||
const elements = SortedArray.ofBounds(start as ElementIndex, chains.offsets[c + 1] as ElementIndex);
|
||||
|
||||
if (singleAtomResidues) {
|
||||
partitionAtomicUnitByAtom(model, elements, builder);
|
||||
partitionAtomicUnitByAtom(model, elements, builder, multiChain);
|
||||
} else if (elements.length > 200000 || isWaterChain(model, c)) {
|
||||
// split up very large chains e.g. lipid bilayers, micelles or water with explicit H
|
||||
partitionAtomicUnitByResidue(model, elements, builder);
|
||||
partitionAtomicUnitByResidue(model, elements, builder, multiChain);
|
||||
} else {
|
||||
builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, elements);
|
||||
builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, elements, multiChain ? Unit.Trait.MultiChain : Unit.Trait.None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,23 +625,27 @@ namespace Structure {
|
||||
return model.entities.data.type.value(e) === 'water';
|
||||
}
|
||||
|
||||
function partitionAtomicUnitByAtom(model: Model, indices: SortedArray, builder: StructureBuilder) {
|
||||
function partitionAtomicUnitByAtom(model: Model, indices: SortedArray, builder: StructureBuilder, multiChain: boolean) {
|
||||
const { x, y, z } = model.atomicConformation;
|
||||
const lookup = GridLookup3D({ x, y, z, indices }, 8192);
|
||||
const { offset, count, array } = lookup.buckets;
|
||||
|
||||
const traits = (multiChain ? Unit.Trait.MultiChain : Unit.Trait.None) | (offset.length > 1 ? Unit.Trait.Patitioned : Unit.Trait.None);
|
||||
|
||||
builder.beginChainGroup();
|
||||
for (let i = 0, _i = offset.length; i < _i; i++) {
|
||||
const start = offset[i];
|
||||
const set = new Int32Array(count[i]);
|
||||
for (let j = 0, _j = count[i]; j < _j; j++) {
|
||||
set[j] = indices[array[start + j]];
|
||||
}
|
||||
builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, SortedArray.ofSortedArray(set));
|
||||
builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, SortedArray.ofSortedArray(set), traits);
|
||||
}
|
||||
builder.endChainGroup();
|
||||
}
|
||||
|
||||
// keeps atoms of residues together
|
||||
function partitionAtomicUnitByResidue(model: Model, indices: SortedArray, builder: StructureBuilder) {
|
||||
function partitionAtomicUnitByResidue(model: Model, indices: SortedArray, builder: StructureBuilder, multiChain: boolean) {
|
||||
const { residueAtomSegments } = model.atomicHierarchy
|
||||
|
||||
const startIndices: number[] = []
|
||||
@@ -644,6 +665,9 @@ namespace Structure {
|
||||
const lookup = GridLookup3D({ x, y, z, indices: SortedArray.ofSortedArray(startIndices) }, gridCellCount);
|
||||
const { offset, count, array } = lookup.buckets;
|
||||
|
||||
const traits = (multiChain ? Unit.Trait.MultiChain : Unit.Trait.None) | (offset.length > 1 ? Unit.Trait.Patitioned : Unit.Trait.None);
|
||||
|
||||
builder.beginChainGroup();
|
||||
for (let i = 0, _i = offset.length; i < _i; i++) {
|
||||
const start = offset[i];
|
||||
const set: number[] = [];
|
||||
@@ -653,15 +677,16 @@ namespace Structure {
|
||||
set[set.length] = l;
|
||||
}
|
||||
}
|
||||
builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, SortedArray.ofSortedArray(new Int32Array(set)));
|
||||
builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, SortedArray.ofSortedArray(new Int32Array(set)), traits);
|
||||
}
|
||||
builder.endChainGroup();
|
||||
}
|
||||
|
||||
function addCoarseUnits(builder: StructureBuilder, model: Model, elements: CoarseElements, kind: Unit.Kind) {
|
||||
const { chainElementSegments } = elements;
|
||||
for (let cI = 0; cI < chainElementSegments.count; cI++) {
|
||||
const elements = SortedArray.ofBounds<ElementIndex>(chainElementSegments.offsets[cI], chainElementSegments.offsets[cI + 1]);
|
||||
builder.addUnit(kind, model, SymmetryOperator.Default, elements);
|
||||
builder.addUnit(kind, model, SymmetryOperator.Default, elements, Unit.Trait.None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,9 +710,22 @@ namespace Structure {
|
||||
private units: Unit[] = [];
|
||||
private invariantId = idFactory()
|
||||
|
||||
addUnit(kind: Unit.Kind, model: Model, operator: SymmetryOperator, elements: StructureElement.Set, invariantId?: number): Unit {
|
||||
private chainGroupId = -1;
|
||||
private inChainGroup = false;
|
||||
|
||||
beginChainGroup() {
|
||||
this.chainGroupId++;
|
||||
this.inChainGroup = true;
|
||||
}
|
||||
|
||||
endChainGroup() {
|
||||
this.inChainGroup = false;
|
||||
}
|
||||
|
||||
addUnit(kind: Unit.Kind, model: Model, operator: SymmetryOperator, elements: StructureElement.Set, traits: Unit.Traits, invariantId?: number): Unit {
|
||||
if (invariantId === undefined) invariantId = this.invariantId()
|
||||
const unit = Unit.create(this.units.length, invariantId, kind, model, operator, elements);
|
||||
const chainGroupId = this.inChainGroup ? this.chainGroupId : ++this.chainGroupId;
|
||||
const unit = Unit.create(this.units.length, invariantId, chainGroupId, traits, kind, model, operator, elements);
|
||||
this.units.push(unit);
|
||||
return unit;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Model } from '../model'
|
||||
import { GridLookup3D, Lookup3D } from '../../../mol-math/geometry'
|
||||
import { IntraUnitLinks, computeIntraUnitBonds } from './unit/links'
|
||||
import { CoarseElements, CoarseSphereConformation, CoarseGaussianConformation } from '../model/properties/coarse';
|
||||
import { ValueRef } from '../../../mol-util';
|
||||
import { ValueRef, BitFlags } from '../../../mol-util';
|
||||
import { UnitRings } from './unit/rings';
|
||||
import StructureElement from './element'
|
||||
import { ChainIndex, ResidueIndex, ElementIndex } from '../model/indexing';
|
||||
@@ -33,11 +33,11 @@ namespace Unit {
|
||||
export function isSpheres(u: Unit): u is Spheres { return u.kind === Kind.Spheres; }
|
||||
export function isGaussians(u: Unit): u is Gaussians { return u.kind === Kind.Gaussians; }
|
||||
|
||||
export function create(id: number, invariantId: number, kind: Kind, model: Model, operator: SymmetryOperator, elements: StructureElement.Set): Unit {
|
||||
export function create(id: number, invariantId: number, chainGroupId: number, traits: Traits, kind: Kind, model: Model, operator: SymmetryOperator, elements: StructureElement.Set): Unit {
|
||||
switch (kind) {
|
||||
case Kind.Atomic: return new Atomic(id, invariantId, model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation, void 0), AtomicProperties());
|
||||
case Kind.Spheres: return createCoarse(id, invariantId, model, Kind.Spheres, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.spheres, getSphereRadiusFunc(model)), CoarseProperties());
|
||||
case Kind.Gaussians: return createCoarse(id, invariantId, model, Kind.Gaussians, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.gaussians, getGaussianRadiusFunc(model)), CoarseProperties());
|
||||
case Kind.Atomic: return new Atomic(id, invariantId, chainGroupId, traits, model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation, void 0), AtomicProperties());
|
||||
case Kind.Spheres: return createCoarse(id, invariantId, chainGroupId, traits, model, Kind.Spheres, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.spheres, getSphereRadiusFunc(model)), CoarseProperties());
|
||||
case Kind.Gaussians: return createCoarse(id, invariantId, chainGroupId, traits, model, Kind.Gaussians, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.gaussians, getGaussianRadiusFunc(model)), CoarseProperties());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,10 +94,23 @@ namespace Unit {
|
||||
return hash2(u.invariantId, SortedArray.hashCode(u.elements));
|
||||
}
|
||||
|
||||
export type Traits = BitFlags<Trait>
|
||||
export const enum Trait {
|
||||
None = 0x0,
|
||||
MultiChain = 0x1,
|
||||
Patitioned = 0x2
|
||||
}
|
||||
export namespace Traits {
|
||||
export const is: (t: Traits, f: Trait) => boolean = BitFlags.has
|
||||
export const create: (f: Trait) => Traits = BitFlags.create
|
||||
}
|
||||
|
||||
export interface Base {
|
||||
readonly id: number,
|
||||
/** invariant ID stays the same even if the Operator/conformation changes. */
|
||||
readonly invariantId: number,
|
||||
readonly chainGroupId: number,
|
||||
readonly traits: Traits,
|
||||
readonly elements: StructureElement.Set,
|
||||
readonly model: Model,
|
||||
readonly conformation: SymmetryOperator.ArrayMapping<ElementIndex>,
|
||||
@@ -139,24 +152,28 @@ namespace Unit {
|
||||
|
||||
readonly id: number;
|
||||
readonly invariantId: number;
|
||||
/** Used to identify a single chain split into multiple units. */
|
||||
readonly chainGroupId: number;
|
||||
readonly traits: Traits;
|
||||
readonly elements: StructureElement.Set;
|
||||
readonly model: Model;
|
||||
readonly conformation: SymmetryOperator.ArrayMapping<ElementIndex>;
|
||||
|
||||
/** Reference some commonly accessed things for faster access. */
|
||||
/** Reference `residueIndex` from `model` for faster access. */
|
||||
readonly residueIndex: ArrayLike<ResidueIndex>;
|
||||
/** Reference `chainIndex` from `model` for faster access. */
|
||||
readonly chainIndex: ArrayLike<ChainIndex>;
|
||||
|
||||
private props: AtomicProperties;
|
||||
|
||||
getChild(elements: StructureElement.Set): Unit {
|
||||
if (elements.length === this.elements.length) return this;
|
||||
return new Atomic(this.id, this.invariantId, this.model, elements, this.conformation, AtomicProperties());
|
||||
return new Atomic(this.id, this.invariantId, this.chainGroupId, this.traits, this.model, elements, this.conformation, AtomicProperties());
|
||||
}
|
||||
|
||||
applyOperator(id: number, operator: SymmetryOperator, dontCompose = false): Unit {
|
||||
const op = dontCompose ? operator : SymmetryOperator.compose(this.conformation.operator, operator);
|
||||
return new Atomic(id, this.invariantId, this.model, this.elements, SymmetryOperator.createMapping(op, this.model.atomicConformation, this.conformation.r), this.props);
|
||||
return new Atomic(id, this.invariantId, this.chainGroupId, this.traits, this.model, this.elements, SymmetryOperator.createMapping(op, this.model.atomicConformation, this.conformation.r), this.props);
|
||||
}
|
||||
|
||||
get lookup3d() {
|
||||
@@ -220,9 +237,11 @@ namespace Unit {
|
||||
return this.model.atomicHierarchy.residueAtomSegments.index[this.elements[elementIndex]];
|
||||
}
|
||||
|
||||
constructor(id: number, invariantId: number, model: Model, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping<ElementIndex>, props: AtomicProperties) {
|
||||
constructor(id: number, invariantId: number, chainGroupId: number, traits: Traits, model: Model, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping<ElementIndex>, props: AtomicProperties) {
|
||||
this.id = id;
|
||||
this.invariantId = invariantId;
|
||||
this.chainGroupId = chainGroupId;
|
||||
this.traits = traits;
|
||||
this.model = model;
|
||||
this.elements = elements;
|
||||
this.conformation = conformation;
|
||||
@@ -263,6 +282,8 @@ namespace Unit {
|
||||
|
||||
readonly id: number;
|
||||
readonly invariantId: number;
|
||||
readonly chainGroupId: number;
|
||||
readonly traits: Traits;
|
||||
readonly elements: StructureElement.Set;
|
||||
readonly model: Model;
|
||||
readonly conformation: SymmetryOperator.ArrayMapping<ElementIndex>;
|
||||
@@ -274,12 +295,12 @@ namespace Unit {
|
||||
|
||||
getChild(elements: StructureElement.Set): Unit {
|
||||
if (elements.length === this.elements.length) return this as any as Unit /** lets call this an ugly temporary hack */;
|
||||
return createCoarse(this.id, this.invariantId, this.model, this.kind, elements, this.conformation, CoarseProperties());
|
||||
return createCoarse(this.id, this.invariantId, this.chainGroupId, this.traits, this.model, this.kind, elements, this.conformation, CoarseProperties());
|
||||
}
|
||||
|
||||
applyOperator(id: number, operator: SymmetryOperator, dontCompose = false): Unit {
|
||||
const op = dontCompose ? operator : SymmetryOperator.compose(this.conformation.operator, operator);
|
||||
const ret = createCoarse(id, this.invariantId, this.model, this.kind, this.elements, SymmetryOperator.createMapping(op, this.getCoarseConformation(), this.conformation.r), this.props);
|
||||
const ret = createCoarse(id, this.invariantId, this.chainGroupId, this.traits, this.model, this.kind, this.elements, SymmetryOperator.createMapping(op, this.getCoarseConformation(), this.conformation.r), this.props);
|
||||
// (ret as Coarse<K, C>)._lookup3d = this._lookup3d;
|
||||
return ret;
|
||||
}
|
||||
@@ -308,11 +329,13 @@ namespace Unit {
|
||||
return this.kind === Kind.Spheres ? this.model.coarseConformation.spheres : this.model.coarseConformation.gaussians;
|
||||
}
|
||||
|
||||
constructor(id: number, invariantId: number, model: Model, kind: K, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping<ElementIndex>, props: CoarseProperties) {
|
||||
constructor(id: number, invariantId: number, chainGroupId: number, traits: Traits, model: Model, kind: K, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping<ElementIndex>, props: CoarseProperties) {
|
||||
this.kind = kind;
|
||||
this.objectPrimitive = kind === Kind.Spheres ? 'sphere' : 'gaussian'
|
||||
this.id = id;
|
||||
this.invariantId = invariantId;
|
||||
this.chainGroupId = chainGroupId;
|
||||
this.traits = traits;
|
||||
this.model = model;
|
||||
this.elements = elements;
|
||||
this.conformation = conformation;
|
||||
@@ -336,12 +359,16 @@ namespace Unit {
|
||||
};
|
||||
}
|
||||
|
||||
function createCoarse<K extends Kind.Gaussians | Kind.Spheres>(id: number, invariantId: number, model: Model, kind: K, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping<ElementIndex>, props: CoarseProperties): Unit {
|
||||
return new Coarse(id, invariantId, model, kind, elements, conformation, props) as any as Unit /** lets call this an ugly temporary hack */;
|
||||
function createCoarse<K extends Kind.Gaussians | Kind.Spheres>(id: number, invariantId: number, chainGroupId: number, traits: Traits, model: Model, kind: K, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping<ElementIndex>, props: CoarseProperties): Unit {
|
||||
return new Coarse(id, invariantId, chainGroupId, traits, model, kind, elements, conformation, props) as any as Unit /** lets call this an ugly temporary hack */;
|
||||
}
|
||||
|
||||
export class Spheres extends Coarse<Kind.Spheres, CoarseSphereConformation> { }
|
||||
export class Gaussians extends Coarse<Kind.Gaussians, CoarseGaussianConformation> { }
|
||||
|
||||
export function areSameChainOperatorGroup(a: Unit, b: Unit) {
|
||||
return a.chainGroupId === b.chainGroupId && a.conformation.operator.name === b.conformation.operator.name;
|
||||
}
|
||||
}
|
||||
|
||||
export default Unit;
|
||||
@@ -89,7 +89,9 @@ function createCrossLinkRestraint(unitA: Unit, indexA: StructureElement.UnitInde
|
||||
|
||||
function extractCrossLinkRestraints(structure: Structure): PairRestraints<CrossLinkRestraint> {
|
||||
const pairs: CrossLinkRestraint[] = []
|
||||
if (!structure.models.some(m => IHMCrossLinkRestraint.fromModel(m))) return new PairRestraints(pairs)
|
||||
if (!structure.models.some(m => IHMCrossLinkRestraint.fromModel(m))) {
|
||||
return new PairRestraints(pairs)
|
||||
}
|
||||
|
||||
const n = structure.units.length
|
||||
for (let i = 0; i < n; ++i) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export function getAtomicPolymerElements(unit: Unit.Atomic) {
|
||||
const { elements, model } = unit
|
||||
const { residueAtomSegments } = unit.model.atomicHierarchy
|
||||
const { traceElementIndex } = model.atomicHierarchy.derived.residue
|
||||
const polymerIt = SortedRanges.transientSegments(unit.model.atomicHierarchy.polymerRanges, elements)
|
||||
const polymerIt = SortedRanges.transientSegments(unit.model.atomicRanges.polymerRanges, elements)
|
||||
const residueIt = Segmentation.transientSegments(residueAtomSegments, elements)
|
||||
while (polymerIt.hasNext) {
|
||||
const polymerSegment = polymerIt.move()
|
||||
@@ -51,7 +51,7 @@ export function getAtomicGapElements(unit: Unit.Atomic) {
|
||||
const { elements, model, residueIndex } = unit
|
||||
const { residueAtomSegments } = unit.model.atomicHierarchy
|
||||
const { traceElementIndex } = model.atomicHierarchy.derived.residue
|
||||
const gapIt = SortedRanges.transientSegments(unit.model.atomicHierarchy.gapRanges, unit.elements);
|
||||
const gapIt = SortedRanges.transientSegments(unit.model.atomicRanges.gapRanges, unit.elements);
|
||||
while (gapIt.hasNext) {
|
||||
const gapSegment = gapIt.move();
|
||||
const indexStart = residueIndex[elements[gapSegment.start]]
|
||||
|
||||
@@ -34,6 +34,12 @@ export class StructureUniqueSubsetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
has(parentId: number, e: number) {
|
||||
const unit = this.unitMap.get(parentId);
|
||||
if (!unit) return false;
|
||||
return UniqueArray.has(unit, e);
|
||||
}
|
||||
|
||||
beginUnit(parentId: number) {
|
||||
this.parentId = parentId;
|
||||
if (this.unitMap.has(parentId)) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { Model, ResidueIndex, ElementIndex } from './model';
|
||||
import { MoleculeType, AtomRole, MoleculeTypeAtomRoleId, getMoleculeType } from './model/types';
|
||||
import { MoleculeType, AtomRole, PolymerTypeAtomRoleId, getMoleculeType, PolymerType } from './model/types';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { Unit } from './structure';
|
||||
import Matrix from '../../mol-math/linear-algebra/matrix/matrix';
|
||||
@@ -28,7 +28,7 @@ export function getElementMoleculeType(unit: Unit, element: ElementIndex): Molec
|
||||
const cc = unit.model.properties.chemicalComponentMap.get(compId)
|
||||
if (cc) return getMoleculeType(cc.type, compId)
|
||||
}
|
||||
return MoleculeType.unknown
|
||||
return MoleculeType.Unknown
|
||||
}
|
||||
|
||||
export function getAtomicMoleculeType(model: Model, rI: ResidueIndex): MoleculeType {
|
||||
@@ -36,10 +36,10 @@ export function getAtomicMoleculeType(model: Model, rI: ResidueIndex): MoleculeT
|
||||
}
|
||||
|
||||
const EmptyAtomIds = new Set<string>()
|
||||
export function getAtomIdForAtomRole(moleculeType: MoleculeType, atomRole: AtomRole) {
|
||||
const m = MoleculeTypeAtomRoleId[moleculeType]
|
||||
if (m !== undefined) {
|
||||
const a = m[atomRole]
|
||||
export function getAtomIdForAtomRole(polymerType: PolymerType, atomRole: AtomRole) {
|
||||
const p = PolymerTypeAtomRoleId[polymerType]
|
||||
if (p !== undefined) {
|
||||
const a = p[atomRole]
|
||||
if (a !== undefined) return a
|
||||
}
|
||||
return EmptyAtomIds
|
||||
@@ -81,7 +81,7 @@ export function elementLabel(model: Model, index: ElementIndex) {
|
||||
// }
|
||||
|
||||
const matrixPos = Vec3.zero()
|
||||
export function getPositionMatrix(unit: Unit, indices: ArrayLike<number>) {
|
||||
export function getPositionMatrix(unit: Unit, indices: ArrayLike<number>): Matrix<3, number> {
|
||||
const pos = unit.conformation.position
|
||||
const mat = Matrix.create(3, indices.length)
|
||||
const { elements } = unit
|
||||
|
||||
@@ -10,13 +10,17 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { PluginBehavior } from '../behavior';
|
||||
import { ButtonsType, ModifiersKeys } from '../../../mol-util/input/input-observer';
|
||||
import { Binding } from '../../../mol-util/binding';
|
||||
import { PluginCommands } from '../../command';
|
||||
|
||||
const B = ButtonsType
|
||||
const M = ModifiersKeys
|
||||
const Trigger = Binding.Trigger
|
||||
|
||||
const DefaultFocusLociBindings = {
|
||||
clickCenterFocus: Binding(Trigger(B.Flag.Primary, M.create()), 'Center and focus the clicked element using ${trigger}.'),
|
||||
clickCenterFocus: Binding([
|
||||
Trigger(B.Flag.Auxilary, M.create()),
|
||||
Trigger(B.Flag.Primary, M.create({ alt: true }))
|
||||
], 'Center and focus the clicked element using ${triggers}.'),
|
||||
}
|
||||
const FocusLociParams = {
|
||||
minRadius: PD.Numeric(8, { min: 1, max: 50, step: 1 }),
|
||||
@@ -34,13 +38,17 @@ export const FocusLoci = PluginBehavior.create<FocusLociProps>({
|
||||
register(): void {
|
||||
this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, buttons, modifiers }) => {
|
||||
if (!this.ctx.canvas3d) return;
|
||||
|
||||
const p = this.params;
|
||||
if (Binding.match(this.params.bindings.clickCenterFocus, buttons, modifiers)) {
|
||||
const sphere = Loci.getBoundingSphere(current.loci);
|
||||
if (sphere) {
|
||||
const radius = Math.max(sphere.radius + p.extraRadius, p.minRadius);
|
||||
this.ctx.canvas3d.camera.focus(sphere.center, radius, p.durationMs);
|
||||
const loci = Loci.normalize(current.loci, this.ctx.interactivity.props.granularity)
|
||||
if (Loci.isEmpty(loci)) {
|
||||
PluginCommands.Camera.Reset.dispatch(this.ctx, { })
|
||||
} else {
|
||||
const sphere = Loci.getBoundingSphere(loci);
|
||||
if (sphere) {
|
||||
const radius = Math.max(sphere.radius + p.extraRadius, p.minRadius);
|
||||
this.ctx.canvas3d.camera.focus(sphere.center, radius, p.durationMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -37,6 +37,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
|
||||
|
||||
switch (loci.kind) {
|
||||
case 'element-loci':
|
||||
if (loci.elements.length === 0) return void 0;
|
||||
const e = loci.elements[0];
|
||||
const u = e.unit;
|
||||
if (!u.model.customProperties.has(StructureQualityReport.Descriptor)) return void 0;
|
||||
|
||||
@@ -159,7 +159,7 @@ export const SceneLabels = PluginBehavior.create<SceneLabelsProps>({
|
||||
|
||||
if (p.levels.includes('ligand') && !u.polymerElements.length) {
|
||||
const moleculeType = getElementMoleculeType(u, u.elements[0])
|
||||
if (moleculeType === MoleculeType.other || moleculeType === MoleculeType.saccharide) {
|
||||
if (moleculeType === MoleculeType.Other || moleculeType === MoleculeType.Saccharide) {
|
||||
label = `${StructureProperties.entity.pdbx_description(l).join(', ')} (${getAsymId(u)(l)})`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { StateSelection } from '../../../mol-state';
|
||||
import { ButtonsType, ModifiersKeys } from '../../../mol-util/input/input-observer';
|
||||
import { Binding } from '../../../mol-util/binding';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { EmptyLoci } from '../../../mol-model/loci';
|
||||
import { EmptyLoci, Loci } from '../../../mol-model/loci';
|
||||
|
||||
const B = ButtonsType
|
||||
const M = ModifiersKeys
|
||||
@@ -25,8 +25,8 @@ const Trigger = Binding.Trigger
|
||||
//
|
||||
|
||||
const DefaultHighlightLociBindings = {
|
||||
hoverHighlightOnly: Binding(Trigger(B.Flag.None), 'Highlight hovered element using ${trigger}'),
|
||||
hoverHighlightOnlyExtend: Binding(Trigger(B.Flag.None, M.create({ shift: true })), 'Extend highlight from selected to hovered element along polymer using ${trigger}'),
|
||||
hoverHighlightOnly: Binding([Trigger(B.Flag.None)], 'Highlight hovered element using ${triggers}'),
|
||||
hoverHighlightOnlyExtend: Binding([Trigger(B.Flag.None, M.create({ shift: true }))], 'Extend highlight from selected to hovered element along polymer using ${triggers}'),
|
||||
}
|
||||
const HighlightLociParams = {
|
||||
bindings: PD.Value(DefaultHighlightLociBindings, { isHidden: true }),
|
||||
@@ -74,10 +74,11 @@ export const HighlightLoci = PluginBehavior.create({
|
||||
|
||||
const DefaultSelectLociBindings = {
|
||||
clickSelect: Binding.Empty,
|
||||
clickSelectExtend: Binding(Trigger(B.Flag.Primary, M.create({ shift: true })), 'Extend selection to clicked element along polymer using ${trigger}.'),
|
||||
clickSelectOnly: Binding(Trigger(B.Flag.Secondary, M.create({ control: true })), 'Select only the clicked element using ${trigger}.'),
|
||||
clickSelectToggle: Binding(Trigger(B.Flag.Primary, M.create({ control: true })), 'Toggle selection of clicked element using ${trigger}.'),
|
||||
clickSelectExtend: Binding([Trigger(B.Flag.Primary, M.create({ shift: true }))], 'Extend selection to clicked element along polymer using ${triggers}.'),
|
||||
clickSelectOnly: Binding.Empty,
|
||||
clickSelectToggle: Binding([Trigger(B.Flag.Primary, M.create())], 'Toggle selection of clicked element using ${triggers}.'),
|
||||
clickDeselect: Binding.Empty,
|
||||
clickDeselectAllOnEmpty: Binding([Trigger(B.Flag.Primary)], 'Deselect all when clicking on nothing using ${triggers}.'),
|
||||
}
|
||||
const SelectLociParams = {
|
||||
bindings: PD.Value(DefaultSelectLociBindings, { isHidden: true }),
|
||||
@@ -127,6 +128,10 @@ export const SelectLoci = PluginBehavior.create({
|
||||
if (Binding.match(this.params.bindings.clickDeselect, buttons, modifiers)) {
|
||||
this.ctx.interactivity.lociSelects.deselect(current)
|
||||
}
|
||||
|
||||
if (Binding.match(this.params.bindings.clickDeselectAllOnEmpty, buttons, modifiers)) {
|
||||
if (Loci.isEmpty(current.loci)) this.ctx.interactivity.lociSelects.deselectAll()
|
||||
}
|
||||
});
|
||||
this.ctx.interactivity.lociSelects.addProvider(this.lociMarkProvider)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ const M = ModifiersKeys
|
||||
const Trigger = Binding.Trigger
|
||||
|
||||
const DefaultStructureRepresentationInteractionBindings = {
|
||||
clickInteractionAroundOnly: Binding(Trigger(B.Flag.Secondary, M.create()), 'Show the structure interaction around only the clicked element using ${trigger}.'),
|
||||
clickInteractionAroundOnly: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Show the structure interaction around only the clicked element using ${triggers}.'),
|
||||
}
|
||||
const StructureRepresentationInteractionParams = {
|
||||
bindings: PD.Value(DefaultStructureRepresentationInteractionBindings, { isHidden: true }),
|
||||
@@ -47,16 +47,16 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
|
||||
|
||||
private createResVisualParams(s: Structure) {
|
||||
return StructureRepresentation3DHelpers.createParams(this.plugin, s, {
|
||||
repr: BuiltInStructureRepresentations['ball-and-stick'],
|
||||
size: [BuiltInSizeThemes.uniform, () => ({ value: 0.85 } )]
|
||||
repr: [BuiltInStructureRepresentations['ball-and-stick'], () => ({ sizeAspectRatio: 1 })],
|
||||
size: [BuiltInSizeThemes.uniform, () => ({ value: 0.6 } )]
|
||||
});
|
||||
}
|
||||
|
||||
private createSurVisualParams(s: Structure) {
|
||||
return StructureRepresentation3DHelpers.createParams(this.plugin, s, {
|
||||
repr: BuiltInStructureRepresentations['ball-and-stick'],
|
||||
repr: [BuiltInStructureRepresentations['ball-and-stick'], () => ({ sizeAspectRatio: 1 })],
|
||||
color: [BuiltInColorThemes['element-symbol'], () => ({ saturation: -3, lightness: 0.6 })],
|
||||
size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )]
|
||||
size: [BuiltInSizeThemes.uniform, () => ({ value: 0.3 } )]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
|
||||
|
||||
// Selections
|
||||
if (!refs[Tags.ResidueSel]) {
|
||||
refs[Tags.ResidueSel] = builder.to(refs['structure-interaction-group']).apply(StateTransforms.Model.StructureSelectionFromExpression,
|
||||
{ expression: { } as any, label: 'Residue' }, { tags: Tags.ResidueSel }).ref;
|
||||
refs[Tags.ResidueSel] = builder.to(refs['structure-interaction-group']).apply(StateTransforms.Model.StructureSelectionFromBundle,
|
||||
{ bundle: { } as any, label: 'Residue' }, { tags: Tags.ResidueSel }).ref;
|
||||
}
|
||||
|
||||
if (!refs[Tags.SurrSel]) {
|
||||
@@ -102,13 +102,14 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
|
||||
if (groups.length === 0) return;
|
||||
|
||||
const update = state.build();
|
||||
const bundle = StructureElement.Bundle.Empty;
|
||||
const expression = MS.struct.generator.empty();
|
||||
for (const g of groups) {
|
||||
// TODO: update props of the group node to ghost
|
||||
|
||||
const res = StateSelection.findTagInSubtree(state.tree, g.transform.ref, Tags.ResidueSel);
|
||||
const surr = StateSelection.findTagInSubtree(state.tree, g.transform.ref, Tags.SurrSel);
|
||||
if (res) update.to(res).update(StateTransforms.Model.StructureSelectionFromExpression, old => ({ ...old, expression }));
|
||||
if (res) update.to(res).update(StateTransforms.Model.StructureSelectionFromBundle, old => ({ ...old, bundle }));
|
||||
if (surr) update.to(surr).update(StateTransforms.Model.StructureSelectionFromExpression, old => ({ ...old, expression }));
|
||||
}
|
||||
|
||||
@@ -148,7 +149,7 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
|
||||
} else if (Link.isLoci(current.loci)) {
|
||||
loci = Link.toStructureElementLoci(current.loci);
|
||||
} else if (Structure.isLoci(current.loci)) {
|
||||
loci = Structure.toStructureElementLoci(current.loci);
|
||||
loci = Structure.toStructureElementLoci(current.loci.structure);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -166,19 +167,18 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
|
||||
|
||||
lastLoci = loci;
|
||||
|
||||
const core = MS.struct.modifier.wholeResidues([
|
||||
StructureElement.Loci.toExpression(loci)
|
||||
]);
|
||||
const residueLoci = StructureElement.Loci.extendToWholeResidues(StructureElement.Loci.remap(loci, parent.obj!.data))
|
||||
const residueBundle = StructureElement.Bundle.fromLoci(residueLoci)
|
||||
|
||||
const surroundings = MS.struct.modifier.includeSurroundings({
|
||||
0: core,
|
||||
0: StructureElement.Bundle.toExpression(residueBundle),
|
||||
radius: 5,
|
||||
'as-whole-residues': true
|
||||
});
|
||||
|
||||
const { state, builder, refs } = this.ensureShape(parent);
|
||||
|
||||
builder.to(refs[Tags.ResidueSel]!).update(StateTransforms.Model.StructureSelectionFromExpression, old => ({ ...old, expression: core }));
|
||||
builder.to(refs[Tags.ResidueSel]!).update(StateTransforms.Model.StructureSelectionFromBundle, old => ({ ...old, bundle: residueBundle }));
|
||||
builder.to(refs[Tags.SurrSel]!).update(StateTransforms.Model.StructureSelectionFromExpression, old => ({ ...old, expression: surroundings }));
|
||||
|
||||
PluginCommands.State.Update.dispatch(this.plugin, { state, tree: builder, options: { doNotLogTiming: true, doNotUpdateCurrent: true } });
|
||||
|
||||
@@ -34,12 +34,20 @@ const Trigger = Binding.Trigger
|
||||
export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { }
|
||||
|
||||
export namespace VolumeStreaming {
|
||||
function channelParam(label: string, color: Color, defaultValue: VolumeIsoValue, stats: VolumeData['dataStats']) {
|
||||
return PD.Group({
|
||||
isoValue: createIsoValueParam(defaultValue, stats),
|
||||
color: PD.Color(color),
|
||||
wireframe: PD.Boolean(false),
|
||||
opacity: PD.Numeric(0.3, { min: 0, max: 1, step: 0.01 })
|
||||
|
||||
export interface ChannelParams {
|
||||
isoValue: VolumeIsoValue,
|
||||
color: Color,
|
||||
wireframe: boolean,
|
||||
opacity: number
|
||||
}
|
||||
|
||||
function channelParam(label: string, color: Color, defaultValue: VolumeIsoValue, stats: VolumeData['dataStats'], defaults: Partial<ChannelParams> = {}) {
|
||||
return PD.Group<ChannelParams>({
|
||||
isoValue: createIsoValueParam(typeof defaults.isoValue !== 'undefined' ? defaults.isoValue : defaultValue, stats),
|
||||
color: PD.Color(typeof defaults.color !== 'undefined' ? defaults.color : color),
|
||||
wireframe: PD.Boolean(typeof defaults.wireframe !== 'undefined' ? defaults.wireframe : false),
|
||||
opacity: PD.Numeric(typeof defaults.opacity !== 'undefined' ? defaults.opacity : 0.3, { min: 0, max: 1, step: 0.01 })
|
||||
}, { label, isExpanded: true });
|
||||
}
|
||||
|
||||
@@ -51,54 +59,67 @@ export namespace VolumeStreaming {
|
||||
};
|
||||
|
||||
export const DefaultBindings = {
|
||||
clickVolumeAroundOnly: Binding(Trigger(B.Flag.Secondary, M.create()), 'Show the volume around only the clicked element using ${trigger}.'),
|
||||
clickVolumeAroundOnly: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Show the volume around only the clicked element using ${triggers}.'),
|
||||
}
|
||||
|
||||
export function createParams(data?: VolumeServerInfo.Data, defaultView?: ViewTypes, binding?: typeof DefaultBindings) {
|
||||
export function createParams(options: { data?: VolumeServerInfo.Data, defaultView?: ViewTypes, binding?: typeof DefaultBindings, channelParams?: DefaultChannelParams } = { }) {
|
||||
const { data, defaultView, binding, channelParams } = options;
|
||||
const map = new Map<string, VolumeServerInfo.EntryData>()
|
||||
if (data) data.entries.forEach(d => map.set(d.dataId, d))
|
||||
const names = data ? data.entries.map(d => [d.dataId, d.dataId] as [string, string]) : []
|
||||
const defaultKey = data ? data.entries[0].dataId : ''
|
||||
return {
|
||||
entry: PD.Mapped<EntryParams>(defaultKey, names, name => PD.Group(createEntryParams({ entryData: map.get(name)!, defaultView, structure: data && data.structure, channelParams }))),
|
||||
bindings: PD.Value(binding || DefaultBindings, { isHidden: true }),
|
||||
}
|
||||
}
|
||||
|
||||
export type EntryParamDefinition = typeof createEntryParams extends (...args: any[]) => (infer T) ? T : never
|
||||
export type EntryParams = EntryParamDefinition extends PD.Params ? PD.Values<EntryParamDefinition> : {}
|
||||
|
||||
export function createEntryParams(options: { entryData?: VolumeServerInfo.EntryData, defaultView?: ViewTypes, structure?: Structure, channelParams?: DefaultChannelParams }) {
|
||||
const { entryData, defaultView, structure, channelParams = { } } = options;
|
||||
|
||||
// fake the info
|
||||
const info = data || { kind: 'em', header: { sampling: [fakeSampling], availablePrecisions: [{ precision: 0, maxVoxels: 0 }] }, emDefaultContourLevel: VolumeIsoValue.relative(0) };
|
||||
const box = (data && data.structure.boundary.box) || Box3D.empty();
|
||||
const info = entryData || { kind: 'em', header: { sampling: [fakeSampling], availablePrecisions: [{ precision: 0, maxVoxels: 0 }] }, emDefaultContourLevel: VolumeIsoValue.relative(0) };
|
||||
const box = (structure && structure.boundary.box) || Box3D.empty();
|
||||
|
||||
return {
|
||||
view: PD.MappedStatic(defaultView || (info.kind === 'em' ? 'cell' : 'selection-box'), {
|
||||
'off': PD.Group({}),
|
||||
'off': PD.Group<{}>({}),
|
||||
'box': PD.Group({
|
||||
bottomLeft: PD.Vec3(box.min),
|
||||
topRight: PD.Vec3(box.max),
|
||||
}, { description: 'Static box defined by cartesian coords.', isFlat: true }),
|
||||
'selection-box': PD.Group({
|
||||
radius: PD.Numeric(5, { min: 0, max: 50, step: 0.5 }),
|
||||
radius: PD.Numeric(5, { min: 0, max: 50, step: 0.5 }, { description: 'Radius in \u212B within which the volume is shown.' }),
|
||||
bottomLeft: PD.Vec3(Vec3.create(0, 0, 0), { isHidden: true }),
|
||||
topRight: PD.Vec3(Vec3.create(0, 0, 0), { isHidden: true }),
|
||||
}, { description: 'Box around last-interacted element.', isFlat: true }),
|
||||
'cell': PD.Group({}),
|
||||
// 'auto': PD.Group({ }), // TODO based on camera distance/active selection/whatever, show whole structure or slice.
|
||||
}, { options: ViewTypeOptions as any }),
|
||||
}, { options: ViewTypeOptions, description: 'Controls what of the volume is displayed. "Off" hides the volume alltogether. "Bounded box" shows the volume inside the given box. "Around Interaction" shows the volume around the element/atom last interacted with. "Whole Structure" shows the volume for the whole structure.' }),
|
||||
detailLevel: PD.Select<number>(Math.min(3, info.header.availablePrecisions.length - 1),
|
||||
info.header.availablePrecisions.map((p, i) => [i, `${i + 1} [ ${Math.pow(p.maxVoxels, 1 / 3) | 0}^3 cells ]`] as [number, string])),
|
||||
info.header.availablePrecisions.map((p, i) => [i, `${i + 1} [ ${Math.pow(p.maxVoxels, 1 / 3) | 0}^3 cells ]`] as [number, string]), { description: 'Determines the maximum number of voxels. Depending on the size of the volume options are in the range from 0 (0.52M voxels) to 6 (25.17M voxels).' }),
|
||||
channels: info.kind === 'em'
|
||||
? PD.Group({
|
||||
'em': channelParam('EM', Color(0x638F8F), info.emDefaultContourLevel || VolumeIsoValue.relative(1), info.header.sampling[0].valuesInfo[0])
|
||||
'em': channelParam('EM', Color(0x638F8F), info.emDefaultContourLevel || VolumeIsoValue.relative(1), info.header.sampling[0].valuesInfo[0], channelParams['em'])
|
||||
}, { isFlat: true })
|
||||
: PD.Group({
|
||||
'2fo-fc': channelParam('2Fo-Fc', Color(0x3362B2), VolumeIsoValue.relative(1.5), info.header.sampling[0].valuesInfo[0]),
|
||||
'fo-fc(+ve)': channelParam('Fo-Fc(+ve)', Color(0x33BB33), VolumeIsoValue.relative(3), info.header.sampling[0].valuesInfo[1]),
|
||||
'fo-fc(-ve)': channelParam('Fo-Fc(-ve)', Color(0xBB3333), VolumeIsoValue.relative(-3), info.header.sampling[0].valuesInfo[1]),
|
||||
'2fo-fc': channelParam('2Fo-Fc', Color(0x3362B2), VolumeIsoValue.relative(1.5), info.header.sampling[0].valuesInfo[0], channelParams['2fo-fc']),
|
||||
'fo-fc(+ve)': channelParam('Fo-Fc(+ve)', Color(0x33BB33), VolumeIsoValue.relative(3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(+ve)']),
|
||||
'fo-fc(-ve)': channelParam('Fo-Fc(-ve)', Color(0xBB3333), VolumeIsoValue.relative(-3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(-ve)']),
|
||||
}, { isFlat: true }),
|
||||
bindings: PD.Value(binding || DefaultBindings, { isHidden: true }),
|
||||
};
|
||||
}
|
||||
|
||||
export const ViewTypeOptions = [['off', 'Off'], ['box', 'Bounded Box'], ['selection-box', 'Surroundings'], ['cell', 'Whole Structure']];
|
||||
export const ViewTypeOptions = [['off', 'Off'], ['box', 'Bounded Box'], ['selection-box', 'Around Interaction'], ['cell', 'Whole Structure']] as [ViewTypes, string][];
|
||||
|
||||
export type ViewTypes = 'off' | 'box' | 'selection-box' | 'cell'
|
||||
|
||||
export type ParamDefinition = typeof createParams extends (...args: any[]) => (infer T) ? T : never
|
||||
export type Params = ParamDefinition extends PD.Params ? PD.Values<ParamDefinition> : {}
|
||||
|
||||
type CT = typeof channelParam extends (...args: any[]) => (infer T) ? T : never
|
||||
export type ChannelParams = CT extends PD.Group<infer T> ? T : {}
|
||||
|
||||
type ChannelsInfo = { [name in ChannelType]?: { isoValue: VolumeIsoValue, color: Color, wireframe: boolean, opacity: number } }
|
||||
type ChannelsData = { [name in 'EM' | '2FO-FC' | 'FO-FC']?: VolumeData }
|
||||
|
||||
@@ -113,16 +134,23 @@ export namespace VolumeStreaming {
|
||||
}
|
||||
export type Channels = { [name in ChannelType]?: ChannelInfo }
|
||||
|
||||
export type DefaultChannelParams = { [name in ChannelType]?: Partial<ChannelParams> }
|
||||
|
||||
export class Behavior extends PluginBehavior.WithSubscribers<Params> {
|
||||
private cache = LRUCache.create<ChannelsData>(25);
|
||||
public params: Params = {} as any;
|
||||
private lastLoci: StructureElement.Loci | EmptyLoci = EmptyLoci;
|
||||
private ref: string = '';
|
||||
public infoMap: Map<string, VolumeServerInfo.EntryData>
|
||||
|
||||
channels: Channels = {}
|
||||
|
||||
public get info () {
|
||||
return this.infoMap.get(this.params.entry.name)!
|
||||
}
|
||||
|
||||
private async queryData(box?: Box3D) {
|
||||
let url = urlCombine(this.info.serverUrl, `${this.info.kind}/${this.info.dataId.toLowerCase()}`);
|
||||
let url = urlCombine(this.data.serverUrl, `${this.info.kind}/${this.info.dataId.toLowerCase()}`);
|
||||
|
||||
if (box) {
|
||||
const { min: a, max: b } = box;
|
||||
@@ -132,7 +160,7 @@ export namespace VolumeStreaming {
|
||||
} else {
|
||||
url += `/cell`;
|
||||
}
|
||||
url += `?detail=${this.params.detailLevel}`;
|
||||
url += `?detail=${this.params.entry.params.detailLevel}`;
|
||||
|
||||
let data = LRUCache.get(this.cache, url);
|
||||
if (data) {
|
||||
@@ -165,24 +193,30 @@ export namespace VolumeStreaming {
|
||||
const block = parsed.result.blocks[i];
|
||||
|
||||
const densityServerCif = CIF.schema.densityServer(block);
|
||||
const volume = await this.plugin.runTask(await volumeFromDensityServerData(densityServerCif));
|
||||
const volume = await this.plugin.runTask(volumeFromDensityServerData(densityServerCif));
|
||||
(ret as any)[block.header as any] = volume;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private updateDynamicBox(box: Box3D) {
|
||||
if (this.params.view.name !== 'selection-box') return;
|
||||
if (this.params.entry.params.view.name !== 'selection-box') return;
|
||||
|
||||
const state = this.plugin.state.dataState;
|
||||
const newParams: Params = {
|
||||
...this.params,
|
||||
view: {
|
||||
name: 'selection-box' as 'selection-box',
|
||||
entry: {
|
||||
name: this.params.entry.name,
|
||||
params: {
|
||||
radius: this.params.view.params.radius,
|
||||
bottomLeft: box.min,
|
||||
topRight: box.max
|
||||
...this.params.entry.params,
|
||||
view: {
|
||||
name: 'selection-box' as 'selection-box',
|
||||
params: {
|
||||
radius: this.params.entry.params.view.params.radius,
|
||||
bottomLeft: box.min,
|
||||
topRight: box.max
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -214,7 +248,7 @@ export namespace VolumeStreaming {
|
||||
|
||||
this.subscribeObservable(this.plugin.behaviors.interaction.click, ({ current, buttons, modifiers }) => {
|
||||
if (!Binding.match((this.params.bindings && this.params.bindings.clickVolumeAroundOnly) || DefaultBindings.clickVolumeAroundOnly, buttons, modifiers)) return;
|
||||
if (this.params.view.name !== 'selection-box') {
|
||||
if (this.params.entry.params.view.name !== 'selection-box') {
|
||||
this.lastLoci = this.getNormalizedLoci(current.loci);
|
||||
} else {
|
||||
this.updateInteraction(current);
|
||||
@@ -228,14 +262,14 @@ export namespace VolumeStreaming {
|
||||
} else if (Link.isLoci(loci)) {
|
||||
return Link.toStructureElementLoci(loci);
|
||||
} else if (Structure.isLoci(loci)) {
|
||||
return Structure.toStructureElementLoci(loci);
|
||||
return Structure.toStructureElementLoci(loci.structure);
|
||||
} else {
|
||||
return EmptyLoci;
|
||||
}
|
||||
}
|
||||
|
||||
private getBoxFromLoci(loci: StructureElement.Loci | EmptyLoci): Box3D {
|
||||
if (isEmptyLoci(loci) || StructureElement.Loci.isEmpty(loci)) {
|
||||
if (Loci.isEmpty(loci)) {
|
||||
return Box3D.empty();
|
||||
}
|
||||
|
||||
@@ -272,34 +306,34 @@ export namespace VolumeStreaming {
|
||||
}
|
||||
|
||||
async update(params: Params) {
|
||||
const switchedToSelection = params.view.name === 'selection-box' && this.params && this.params.view && this.params.view.name !== 'selection-box';
|
||||
const switchedToSelection = params.entry.params.view.name === 'selection-box' && this.params && this.params.entry && this.params.entry.params && this.params.entry.params.view && this.params.entry.params.view.name !== 'selection-box';
|
||||
|
||||
this.params = params;
|
||||
|
||||
let box: Box3D | undefined = void 0, emptyData = false;
|
||||
|
||||
switch (params.view.name) {
|
||||
switch (params.entry.params.view.name) {
|
||||
case 'off':
|
||||
emptyData = true;
|
||||
break;
|
||||
case 'box':
|
||||
box = Box3D.create(params.view.params.bottomLeft, params.view.params.topRight);
|
||||
box = Box3D.create(params.entry.params.view.params.bottomLeft, params.entry.params.view.params.topRight);
|
||||
emptyData = Box3D.volume(box) < 0.0001;
|
||||
break;
|
||||
case 'selection-box': {
|
||||
if (switchedToSelection) {
|
||||
box = this.getBoxFromLoci(this.lastLoci) || Box3D.empty();
|
||||
} else {
|
||||
box = Box3D.create(Vec3.clone(params.view.params.bottomLeft), Vec3.clone(params.view.params.topRight));
|
||||
box = Box3D.create(Vec3.clone(params.entry.params.view.params.bottomLeft), Vec3.clone(params.entry.params.view.params.topRight));
|
||||
}
|
||||
const r = params.view.params.radius;
|
||||
const r = params.entry.params.view.params.radius;
|
||||
emptyData = Box3D.volume(box) < 0.0001;
|
||||
Box3D.expand(box, box, Vec3.create(r, r, r));
|
||||
break;
|
||||
}
|
||||
case 'cell':
|
||||
box = this.info.kind === 'x-ray'
|
||||
? this.info.structure.boundary.box
|
||||
? this.data.structure.boundary.box
|
||||
: void 0;
|
||||
break;
|
||||
}
|
||||
@@ -308,7 +342,7 @@ export namespace VolumeStreaming {
|
||||
|
||||
if (!data) return false;
|
||||
|
||||
const info = params.channels as ChannelsInfo;
|
||||
const info = params.entry.params.channels as ChannelsInfo;
|
||||
|
||||
if (this.info.kind === 'x-ray') {
|
||||
this.channels['2fo-fc'] = this.createChannel(data['2FO-FC'] || VolumeData.One, info['2fo-fc'], this.info.header.sampling[0].valuesInfo[0]);
|
||||
@@ -333,14 +367,17 @@ export namespace VolumeStreaming {
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
if (this.params.view.name === 'selection-box') return 'Selection';
|
||||
if (this.params.view.name === 'box') return 'Static Box';
|
||||
if (this.params.view.name === 'cell') return 'Cell';
|
||||
if (this.params.entry.params.view.name === 'selection-box') return 'Selection';
|
||||
if (this.params.entry.params.view.name === 'box') return 'Static Box';
|
||||
if (this.params.entry.params.view.name === 'cell') return 'Cell';
|
||||
return '';
|
||||
}
|
||||
|
||||
constructor(public plugin: PluginContext, public info: VolumeServerInfo.Data) {
|
||||
constructor(public plugin: PluginContext, public data: VolumeServerInfo.Data) {
|
||||
super(plugin, {} as any);
|
||||
|
||||
this.infoMap = new Map<string, VolumeServerInfo.EntryData>()
|
||||
this.data.entries.forEach(info => this.infoMap.set(info.dataId, info))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 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 { PluginStateObject } from '../../../state/objects';
|
||||
@@ -12,13 +13,16 @@ export class VolumeServerInfo extends PluginStateObject.Create<VolumeServerInfo.
|
||||
|
||||
export namespace VolumeServerInfo {
|
||||
export type Kind = 'x-ray' | 'em'
|
||||
export interface Data {
|
||||
serverUrl: string,
|
||||
export interface EntryData {
|
||||
kind: Kind,
|
||||
// for em, the EMDB access code, for x-ray, the PDB id
|
||||
dataId: string,
|
||||
header: VolumeServerHeader,
|
||||
emDefaultContourLevel?: VolumeIsoValue,
|
||||
}
|
||||
export interface Data {
|
||||
serverUrl: string,
|
||||
entries: EntryData[],
|
||||
structure: Structure
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { urlCombine } from '../../../../mol-util/url';
|
||||
import { createIsoValueParam } from '../../../../mol-repr/volume/isosurface';
|
||||
import { VolumeIsoValue } from '../../../../mol-model/volume';
|
||||
import { StateAction, StateObject, StateTransformer } from '../../../../mol-state';
|
||||
import { getStreamingMethod, getId, getContourLevel, getEmdbId } from './util';
|
||||
import { getStreamingMethod, getIds, getContourLevel, getEmdbIds } from './util';
|
||||
import { VolumeStreaming } from './behavior';
|
||||
import { VolumeRepresentation3DHelpers } from '../../../../mol-plugin/state/transforms/representation';
|
||||
import { BuiltInVolumeRepresentations } from '../../../../mol-repr/volume/registry';
|
||||
@@ -22,48 +22,83 @@ import { createTheme } from '../../../../mol-theme/theme';
|
||||
import { Box3D } from '../../../../mol-math/geometry';
|
||||
import { Vec3 } from '../../../../mol-math/linear-algebra';
|
||||
|
||||
function addEntry(entries: InfoEntryProps[], method: VolumeServerInfo.Kind, dataId: string, emDefaultContourLevel: number) {
|
||||
entries.push({
|
||||
source: method === 'em'
|
||||
? { name: 'em', params: { isoValue: VolumeIsoValue.absolute(emDefaultContourLevel || 0) } }
|
||||
: { name: 'x-ray', params: { } },
|
||||
dataId
|
||||
})
|
||||
}
|
||||
|
||||
export const InitVolumeStreaming = StateAction.build({
|
||||
display: { name: 'Volume Streaming' },
|
||||
from: SO.Molecule.Structure,
|
||||
params(a) {
|
||||
const method = getStreamingMethod(a && a.data);
|
||||
const id = getId(a && a.data);
|
||||
const ids = getIds(method, a && a.data);
|
||||
return {
|
||||
method: PD.Select<VolumeServerInfo.Kind>(method, [['em', 'EM'], ['x-ray', 'X-Ray']]),
|
||||
id: PD.Text(id),
|
||||
serverUrl: PD.Text('https://ds.litemol.org'),
|
||||
entries: PD.ObjectList({ id: PD.Text(ids[0] || '') }, ({ id }) => id, { defaultValue: ids.map(id => ({ id })) }),
|
||||
defaultView: PD.Select<VolumeStreaming.ViewTypes>(method === 'em' ? 'cell' : 'selection-box', VolumeStreaming.ViewTypeOptions as any),
|
||||
behaviorRef: PD.Text('', { isHidden: true }),
|
||||
emContourProvider: PD.Select<'wwpdb' | 'pdbe'>('wwpdb', [['wwpdb', 'wwPDB'], ['pdbe', 'PDBe']], { isHidden: true }),
|
||||
bindings: PD.Value(VolumeStreaming.DefaultBindings, { isHidden: true }),
|
||||
options: PD.Group({
|
||||
serverUrl: PD.Text('https://ds.litemol.org'),
|
||||
behaviorRef: PD.Text('', { isHidden: true }),
|
||||
emContourProvider: PD.Select<'wwpdb' | 'pdbe'>('wwpdb', [['wwpdb', 'wwPDB'], ['pdbe', 'PDBe']], { isHidden: true }),
|
||||
bindings: PD.Value(VolumeStreaming.DefaultBindings, { isHidden: true }),
|
||||
channelParams: PD.Value<VolumeStreaming.DefaultChannelParams>({}, { isHidden: true })
|
||||
})
|
||||
};
|
||||
},
|
||||
isApplicable: (a) => a.data.models.length === 1
|
||||
})(({ ref, state, params }, plugin: PluginContext) => Task.create('Volume Streaming', async taskCtx => {
|
||||
let dataId = params.id.toLowerCase(), emDefaultContourLevel: number | undefined;
|
||||
if (params.method === 'em') {
|
||||
await taskCtx.update('Getting EMDB info...');
|
||||
if (!dataId.toUpperCase().startsWith('EMD')) {
|
||||
dataId = await getEmdbId(plugin, taskCtx, dataId)
|
||||
const entries: InfoEntryProps[] = []
|
||||
|
||||
for (let i = 0, il = params.entries.length; i < il; ++i) {
|
||||
let dataId = params.entries[i].id.toLowerCase()
|
||||
let emDefaultContourLevel: number | undefined;
|
||||
|
||||
if (params.method === 'em') {
|
||||
// if pdb ids are given for method 'em', get corresponding emd ids
|
||||
// and continue the loop
|
||||
if (!dataId.toUpperCase().startsWith('EMD')) {
|
||||
await taskCtx.update('Getting EMDB info...');
|
||||
const emdbIds = await getEmdbIds(plugin, taskCtx, dataId)
|
||||
for (let j = 0, jl = emdbIds.length; j < jl; ++j) {
|
||||
const emdbId = emdbIds[j]
|
||||
let contourLevel: number | undefined;
|
||||
try {
|
||||
contourLevel = await getContourLevel(params.options.emContourProvider, plugin, taskCtx, emdbId)
|
||||
} catch (e) {
|
||||
console.info(`Could not get map info for ${emdbId}: ${e}`)
|
||||
continue;
|
||||
}
|
||||
addEntry(entries, params.method, emdbId, contourLevel || 0)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
emDefaultContourLevel = await getContourLevel(params.options.emContourProvider, plugin, taskCtx, dataId);
|
||||
} catch (e) {
|
||||
console.info(`Could not get map info for ${dataId}: ${e}`)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const contourLevel = await getContourLevel(params.emContourProvider, plugin, taskCtx, dataId);
|
||||
emDefaultContourLevel = contourLevel || 0;
|
||||
|
||||
addEntry(entries, params.method, dataId, emDefaultContourLevel || 0)
|
||||
}
|
||||
|
||||
const infoTree = state.build().to(ref)
|
||||
.apply(CreateVolumeStreamingInfo, {
|
||||
serverUrl: params.serverUrl,
|
||||
source: params.method === 'em'
|
||||
? { name: 'em', params: { isoValue: VolumeIsoValue.absolute(emDefaultContourLevel || 0) } }
|
||||
: { name: 'x-ray', params: { } },
|
||||
dataId
|
||||
serverUrl: params.options.serverUrl,
|
||||
entries
|
||||
});
|
||||
|
||||
const infoObj = await state.updateTree(infoTree).runInContext(taskCtx);
|
||||
|
||||
const behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior,
|
||||
PD.getDefaultValues(VolumeStreaming.createParams(infoObj.data, params.defaultView, params.bindings)),
|
||||
{ ref: params.behaviorRef ? params.behaviorRef : void 0 });
|
||||
PD.getDefaultValues(VolumeStreaming.createParams({ data: infoObj.data, defaultView: params.defaultView, binding: params.options.bindings, channelParams: params.options.channelParams })),
|
||||
{ ref: params.options.behaviorRef ? params.options.behaviorRef : void 0 });
|
||||
|
||||
if (params.method === 'em') {
|
||||
behTree.apply(VolumeStreamingVisual, { channel: 'em' }, { state: { isGhost: true } });
|
||||
@@ -78,26 +113,43 @@ export const InitVolumeStreaming = StateAction.build({
|
||||
export const BoxifyVolumeStreaming = StateAction.build({
|
||||
display: { name: 'Boxify Volume Streaming', description: 'Make the current box permanent.' },
|
||||
from: VolumeStreaming,
|
||||
isApplicable: (a) => a.data.params.view.name === 'selection-box'
|
||||
isApplicable: (a) => a.data.params.entry.params.view.name === 'selection-box'
|
||||
})(({ a, ref, state }, plugin: PluginContext) => {
|
||||
const params = a.data.params;
|
||||
if (params.view.name !== 'selection-box') return;
|
||||
const box = Box3D.create(Vec3.clone(params.view.params.bottomLeft), Vec3.clone(params.view.params.topRight));
|
||||
const r = params.view.params.radius;
|
||||
if (params.entry.params.view.name !== 'selection-box') return;
|
||||
const box = Box3D.create(Vec3.clone(params.entry.params.view.params.bottomLeft), Vec3.clone(params.entry.params.view.params.topRight));
|
||||
const r = params.entry.params.view.params.radius;
|
||||
Box3D.expand(box, box, Vec3.create(r, r, r));
|
||||
const newParams: VolumeStreaming.Params = {
|
||||
...params,
|
||||
view: {
|
||||
name: 'box' as 'box',
|
||||
entry: {
|
||||
name: params.entry.name,
|
||||
params: {
|
||||
bottomLeft: box.min,
|
||||
topRight: box.max
|
||||
...params.entry.params,
|
||||
view: {
|
||||
name: 'box' as 'box',
|
||||
params: {
|
||||
bottomLeft: box.min,
|
||||
topRight: box.max
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return state.updateTree(state.build().to(ref).update(newParams));
|
||||
});
|
||||
|
||||
const InfoEntryParams = {
|
||||
dataId: PD.Text(''),
|
||||
source: PD.MappedStatic('x-ray', {
|
||||
'em': PD.Group({
|
||||
isoValue: createIsoValueParam(VolumeIsoValue.relative(1))
|
||||
}),
|
||||
'x-ray': PD.Group({ })
|
||||
})
|
||||
}
|
||||
type InfoEntryProps = PD.Values<typeof InfoEntryParams>
|
||||
|
||||
export { CreateVolumeStreamingInfo }
|
||||
type CreateVolumeStreamingInfo = typeof CreateVolumeStreamingInfo
|
||||
const CreateVolumeStreamingInfo = PluginStateTransform.BuiltIn({
|
||||
@@ -108,30 +160,34 @@ const CreateVolumeStreamingInfo = PluginStateTransform.BuiltIn({
|
||||
params(a) {
|
||||
return {
|
||||
serverUrl: PD.Text('https://ds.litemol.org'),
|
||||
source: PD.MappedStatic('x-ray', {
|
||||
'em': PD.Group({
|
||||
isoValue: createIsoValueParam(VolumeIsoValue.relative(1))
|
||||
}),
|
||||
'x-ray': PD.Group({ })
|
||||
entries: PD.ObjectList<InfoEntryProps>(InfoEntryParams, ({ dataId }) => dataId, {
|
||||
defaultValue: [{ dataId: '', source: { name: 'x-ray', params: {} } }]
|
||||
}),
|
||||
dataId: PD.Text('')
|
||||
};
|
||||
}
|
||||
})({
|
||||
apply: ({ a, params }, plugin: PluginContext) => Task.create('', async taskCtx => {
|
||||
const dataId = params.dataId;
|
||||
const emDefaultContourLevel = params.source.name === 'em' ? params.source.params.isoValue : VolumeIsoValue.relative(1);
|
||||
await taskCtx.update('Getting server header...');
|
||||
const header = await plugin.fetch<VolumeServerHeader>({ url: urlCombine(params.serverUrl, `${params.source.name}/${dataId.toLocaleLowerCase()}`), type: 'json' }).runInContext(taskCtx);
|
||||
const entries: VolumeServerInfo.EntryData[] = []
|
||||
for (let i = 0, il = params.entries.length; i < il; ++i) {
|
||||
const e = params.entries[i]
|
||||
const dataId = e.dataId;
|
||||
const emDefaultContourLevel = e.source.name === 'em' ? e.source.params.isoValue : VolumeIsoValue.relative(1);
|
||||
await taskCtx.update('Getting server header...');
|
||||
const header = await plugin.fetch<VolumeServerHeader>({ url: urlCombine(params.serverUrl, `${e.source.name}/${dataId.toLocaleLowerCase()}`), type: 'json' }).runInContext(taskCtx);
|
||||
entries.push({
|
||||
dataId,
|
||||
kind: e.source.name,
|
||||
header,
|
||||
emDefaultContourLevel
|
||||
})
|
||||
}
|
||||
|
||||
const data: VolumeServerInfo.Data = {
|
||||
serverUrl: params.serverUrl,
|
||||
dataId,
|
||||
kind: params.source.name,
|
||||
header,
|
||||
emDefaultContourLevel,
|
||||
entries,
|
||||
structure: a.data
|
||||
};
|
||||
return new VolumeServerInfo(data, { label: `Volume Server: ${dataId}` });
|
||||
return new VolumeServerInfo(data, { label: 'Volume Server', description: `${entries.map(e => e.dataId). join(', ')}` });
|
||||
})
|
||||
});
|
||||
|
||||
@@ -143,21 +199,29 @@ const CreateVolumeStreamingBehavior = PluginStateTransform.BuiltIn({
|
||||
from: VolumeServerInfo,
|
||||
to: VolumeStreaming,
|
||||
params(a) {
|
||||
return VolumeStreaming.createParams(a && a.data);
|
||||
return VolumeStreaming.createParams({ data: a && a.data });
|
||||
}
|
||||
})({
|
||||
canAutoUpdate: ({ oldParams, newParams }) => {
|
||||
return oldParams.view === newParams.view
|
||||
|| newParams.view.name === 'selection-box'
|
||||
|| newParams.view.name === 'off';
|
||||
return oldParams.entry.params.view === newParams.entry.params.view
|
||||
|| newParams.entry.params.view.name === 'selection-box'
|
||||
|| newParams.entry.params.view.name === 'off';
|
||||
},
|
||||
apply: ({ a, params }, plugin: PluginContext) => Task.create('Volume streaming', async _ => {
|
||||
const behavior = new VolumeStreaming.Behavior(plugin, a.data);
|
||||
await behavior.update(params);
|
||||
return new VolumeStreaming(behavior, { label: 'Volume Streaming', description: behavior.getDescription() });
|
||||
}),
|
||||
update({ b, newParams }) {
|
||||
update({ a, b, oldParams, newParams }) {
|
||||
return Task.create('Update Volume Streaming', async _ => {
|
||||
if (oldParams.entry.name !== newParams.entry.name) {
|
||||
if ('em' in newParams.entry.params.channels) {
|
||||
const { emDefaultContourLevel } = b.data.infoMap.get(newParams.entry.name)!
|
||||
if (emDefaultContourLevel) {
|
||||
newParams.entry.params.channels['em'].isoValue = emDefaultContourLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
const ret = await b.data.update(newParams) ? StateTransformer.UpdateResult.Updated : StateTransformer.UpdateResult.Unchanged;
|
||||
b.description = b.data.getDescription();
|
||||
return ret;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Structure } from '../../../../mol-model/structure';
|
||||
import { Structure, Model } from '../../../../mol-model/structure';
|
||||
import { VolumeServerInfo } from './model';
|
||||
import { PluginContext } from '../../../../mol-plugin/context';
|
||||
import { RuntimeContext } from '../../../../mol-task';
|
||||
@@ -17,28 +17,56 @@ export function getStreamingMethod(s?: Structure, defaultKind: VolumeServerInfo.
|
||||
const model = s.models[0];
|
||||
if (model.sourceData.kind !== 'mmCIF') return defaultKind;
|
||||
|
||||
const data = model.sourceData.data.exptl.method;
|
||||
for (let i = 0; i < data.rowCount; i++) {
|
||||
const v = data.value(i).toUpperCase();
|
||||
if (v.indexOf('MICROSCOPY') >= 0) return 'em';
|
||||
}
|
||||
return 'x-ray';
|
||||
}
|
||||
const { data } = model.sourceData;
|
||||
|
||||
export function getId(s?: Structure): string {
|
||||
if (!s) return ''
|
||||
|
||||
const model = s.models[0]
|
||||
if (model.sourceData.kind !== 'mmCIF') return ''
|
||||
|
||||
const d = model.sourceData.data
|
||||
for (let i = 0, il = d.pdbx_database_related._rowCount; i < il; ++i) {
|
||||
if (d.pdbx_database_related.db_name.value(i).toUpperCase() === 'EMDB') {
|
||||
return d.pdbx_database_related.db_id.value(i)
|
||||
// prefer EMDB entries over structure-factors (SF) e.g. for 'ELECTRON CRYSTALLOGRAPHY' entries
|
||||
// like 6axz or 6kj3 for which EMDB entries are available but map calculation from SF is hard
|
||||
for (let i = 0, il = data.pdbx_database_related._rowCount; i < il; ++i) {
|
||||
if (data.pdbx_database_related.db_name.value(i).toUpperCase() === 'EMDB') {
|
||||
return 'em'
|
||||
}
|
||||
}
|
||||
|
||||
return s.models.length > 0 ? s.models[0].entryId : ''
|
||||
if (data.pdbx_database_status.status_code_sf.isDefined && data.pdbx_database_status.status_code_sf.value(0) === 'REL') {
|
||||
return 'x-ray'
|
||||
}
|
||||
|
||||
// fallbacks
|
||||
for (let i = 0; i < data.exptl.method.rowCount; i++) {
|
||||
const v = data.exptl.method.value(i).toUpperCase();
|
||||
if (v.indexOf('MICROSCOPY') >= 0) return 'em';
|
||||
}
|
||||
return defaultKind;
|
||||
}
|
||||
|
||||
/** Returns EMD ID when available, otherwise falls back to PDB ID */
|
||||
export function getEmIds(model: Model): string[] {
|
||||
const ids: string[] = []
|
||||
if (model.sourceData.kind !== 'mmCIF') return [ model.entryId ]
|
||||
|
||||
const { db_id, db_name, content_type } = model.sourceData.data.pdbx_database_related
|
||||
if (!db_name.isDefined) return [ model.entryId ]
|
||||
|
||||
for (let i = 0, il = db_name.rowCount; i < il; ++i) {
|
||||
if (db_name.value(i).toUpperCase() === 'EMDB' && content_type.value(i) === 'associated EM volume') {
|
||||
ids.push(db_id.value(i))
|
||||
}
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
export function getXrayIds(model: Model): string[] {
|
||||
return [ model.entryId ]
|
||||
}
|
||||
|
||||
export function getIds(method: VolumeServerInfo.Kind, s?: Structure): string[] {
|
||||
if (!s || !s.models.length) return []
|
||||
const model = s.models[0]
|
||||
switch (method) {
|
||||
case 'em': return getEmIds(model)
|
||||
case 'x-ray': return getXrayIds(model)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getContourLevel(provider: 'wwpdb' | 'pdbe', plugin: PluginContext, taskCtx: RuntimeContext, emdbId: string) {
|
||||
@@ -71,21 +99,21 @@ export async function getContourLevelPdbe(plugin: PluginContext, taskCtx: Runtim
|
||||
return contourLevel;
|
||||
}
|
||||
|
||||
export async function getEmdbId(plugin: PluginContext, taskCtx: RuntimeContext, pdbId: string) {
|
||||
export async function getEmdbIds(plugin: PluginContext, taskCtx: RuntimeContext, pdbId: string) {
|
||||
// TODO: parametrize to a differnt URL? in plugin settings perhaps
|
||||
const summary = await plugin.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/${pdbId}`, type: 'json' }).runInContext(taskCtx);
|
||||
|
||||
const summaryEntry = summary && summary[pdbId];
|
||||
let emdbId: string;
|
||||
let emdbIds: string[] = [];
|
||||
if (summaryEntry && summaryEntry[0] && summaryEntry[0].related_structures) {
|
||||
const emdb = summaryEntry[0].related_structures.filter((s: any) => s.resource === 'EMDB');
|
||||
const emdb = summaryEntry[0].related_structures.filter((s: any) => s.resource === 'EMDB' && s.relationship === 'associated EM volume');
|
||||
if (!emdb.length) {
|
||||
throw new Error(`No related EMDB entry found for '${pdbId}'.`);
|
||||
}
|
||||
emdbId = emdb[0].accession;
|
||||
emdbIds.push(...emdb.map((e: { accession: string }) => e.accession));
|
||||
} else {
|
||||
throw new Error(`No related EMDB entry found for '${pdbId}'.`);
|
||||
}
|
||||
|
||||
return emdbId
|
||||
return emdbIds
|
||||
}
|
||||
@@ -106,10 +106,10 @@ export function Highlight(ctx: PluginContext) {
|
||||
const cell = state.select(ref)[0];
|
||||
if (!cell) return;
|
||||
if (SO.Molecule.Structure.is(cell.obj)) {
|
||||
ctx.interactivity.lociHighlights.highlightOnly({ loci: Structure.Loci(cell.obj.data) });
|
||||
ctx.interactivity.lociHighlights.highlightOnly({ loci: Structure.Loci(cell.obj.data) }, false);
|
||||
} else if (cell && SO.isRepresentation3D(cell.obj)) {
|
||||
const loci = SO.Molecule.Structure.is(cell.obj.data.source) ? Structure.Loci(cell.obj.data.source.data) : EveryLoci
|
||||
ctx.interactivity.lociHighlights.highlightOnly({ loci, repr: cell.obj.data.repr });
|
||||
ctx.interactivity.lociHighlights.highlightOnly({ loci, repr: cell.obj.data.repr }, false);
|
||||
}
|
||||
|
||||
// TODO: highlight volumes and shapes?
|
||||
@@ -119,7 +119,7 @@ export function Highlight(ctx: PluginContext) {
|
||||
|
||||
export function ClearHighlight(ctx: PluginContext) {
|
||||
PluginCommands.State.ClearHighlight.subscribe(ctx, ({ state, ref }) => {
|
||||
ctx.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
|
||||
ctx.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci }, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { CustomPropertyRegistry } from '../mol-model-props/common/custom-propert
|
||||
import { StructureRepresentationRegistry } from '../mol-repr/structure/registry';
|
||||
import { VolumeRepresentationRegistry } from '../mol-repr/volume/registry';
|
||||
import { State, StateTransform, StateTransformer } from '../mol-state';
|
||||
import { Task } from '../mol-task';
|
||||
import { Task, Progress } from '../mol-task';
|
||||
import { ColorTheme } from '../mol-theme/color';
|
||||
import { SizeTheme } from '../mol-theme/size';
|
||||
import { ThemeRegistryContext } from '../mol-theme/theme';
|
||||
@@ -176,6 +176,10 @@ export class PluginContext {
|
||||
return this.tasks.run(task);
|
||||
}
|
||||
|
||||
requestTaskAbort(progress: Progress, reason?: string) {
|
||||
this.tasks.requestAbort(progress, reason);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this.disposed) return;
|
||||
this.commands.dispose();
|
||||
|
||||
@@ -50,6 +50,7 @@ export const DefaultPluginSpec: PluginSpec = {
|
||||
PluginSpec.Action(StateTransforms.Model.StructureSelectionFromScript),
|
||||
PluginSpec.Action(StateTransforms.Representation.StructureRepresentation3D),
|
||||
PluginSpec.Action(StateTransforms.Representation.StructureLabels3D),
|
||||
PluginSpec.Action(StateTransforms.Representation.StructureOrientation3D),
|
||||
PluginSpec.Action(StateTransforms.Representation.ModelUnitcell3D),
|
||||
PluginSpec.Action(StateTransforms.Representation.ExplodeStructureRepresentation3D),
|
||||
PluginSpec.Action(StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D),
|
||||
|
||||
@@ -10,13 +10,12 @@ import { PluginComponent } from './component';
|
||||
import { PluginContext } from './context';
|
||||
import { PluginCommands } from './command';
|
||||
|
||||
// TODO: support collapsed state control orientation
|
||||
export type PluginLayoutControlsDisplay = 'outside' | 'portrait' | 'landscape' | 'reactive'
|
||||
export const PluginLayoutStateParams = {
|
||||
isExpanded: PD.Boolean(false),
|
||||
showControls: PD.Boolean(true),
|
||||
outsideControls: PD.Boolean(true, { isHidden: true })
|
||||
controlsDisplay: PD.Value<PluginLayoutControlsDisplay>('outside', { isHidden: true })
|
||||
}
|
||||
|
||||
export type PluginLayoutStateProps = PD.Values<typeof PluginLayoutStateParams>
|
||||
|
||||
interface RootState {
|
||||
@@ -149,22 +148,22 @@ export class PluginLayout extends PluginComponent<PluginLayoutStateProps> {
|
||||
}
|
||||
|
||||
const s = body.style
|
||||
s.top = t.top;
|
||||
s.bottom = t.bottom;
|
||||
s.left = t.left;
|
||||
s.right = t.right;
|
||||
s.top = t.top!;
|
||||
s.bottom = t.bottom!;
|
||||
s.left = t.left!;
|
||||
s.right = t.right!;
|
||||
|
||||
s.width = t.width;
|
||||
s.height = t.height;
|
||||
s.maxWidth = t.maxWidth;
|
||||
s.maxHeight = t.maxHeight;
|
||||
s.margin = t.margin;
|
||||
s.marginLeft = t.marginLeft;
|
||||
s.marginRight = t.marginRight;
|
||||
s.marginTop = t.marginTop;
|
||||
s.marginBottom = t.marginBottom;
|
||||
s.width = t.width!;
|
||||
s.height = t.height!;
|
||||
s.maxWidth = t.maxWidth!;
|
||||
s.maxHeight = t.maxHeight!;
|
||||
s.margin = t.margin!;
|
||||
s.marginLeft = t.marginLeft!;
|
||||
s.marginRight = t.marginRight!;
|
||||
s.marginTop = t.marginTop!;
|
||||
s.marginBottom = t.marginBottom!;
|
||||
|
||||
s.position = t.position;
|
||||
s.position = t.position!;
|
||||
s.overflow = t.overflow || '';
|
||||
|
||||
const doc = this.getScrollElement();
|
||||
@@ -172,7 +171,7 @@ export class PluginLayout extends PluginComponent<PluginLayoutStateProps> {
|
||||
doc.scrollLeft = t.scrollLeft;
|
||||
|
||||
this.rootState = void 0;
|
||||
this.root.style.zIndex = t.zIndex;
|
||||
this.root.style.zIndex = t.zIndex!;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.msp-btn-collapse {
|
||||
padding: 0 $control-spacing / 2;
|
||||
}
|
||||
|
||||
.msp-btn, .msp-btn:active, .msp-btn-link:focus, .msp-btn:hover {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
@@ -13,13 +13,15 @@
|
||||
}
|
||||
|
||||
.msp-sequence-wrapper {
|
||||
word-break: break-word;
|
||||
padding: $info-vertical-padding $control-spacing $info-vertical-padding $control-spacing;
|
||||
word-break: break-all;
|
||||
// use $control-spacing for top to have space for sequence numebrs
|
||||
padding: $control-spacing $control-spacing $info-vertical-padding $control-spacing;
|
||||
user-select: none;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
font-size: 90%;
|
||||
line-height: 180%;
|
||||
}
|
||||
|
||||
.msp-sequence-wrapper-non-empty {
|
||||
@@ -30,4 +32,36 @@
|
||||
span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.msp-sequence-residue-long {
|
||||
margin: 0em 0.2em 0em 0.2em;
|
||||
}
|
||||
|
||||
.msp-sequence-residue-long-begin {
|
||||
margin: 0em 0.2em 0em 0em;
|
||||
}
|
||||
|
||||
.msp-sequence-number {
|
||||
color: $sequence-number-color;
|
||||
word-break: keep-all;
|
||||
cursor: default;
|
||||
position: relative;
|
||||
top: -1.1em;
|
||||
left: 3.1em;
|
||||
padding: 0px;
|
||||
margin-left: -3em;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.msp-sequence-number-long {
|
||||
left: 3.3em;
|
||||
}
|
||||
|
||||
.msp-sequence-number-long-negative {
|
||||
left: 2.7em;
|
||||
}
|
||||
|
||||
.msp-sequence-number-negative {
|
||||
left: 2.5em;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
.msp-task-state {
|
||||
|
||||
|
||||
line-height: $row-height;
|
||||
//height: $row-height;
|
||||
//position: relative;
|
||||
//margin-top: 1px;
|
||||
|
||||
|
||||
> span {
|
||||
@include non-selectable;
|
||||
//display: inline-block;
|
||||
//padding: 0 $control-spacing;
|
||||
}
|
||||
|
||||
|
||||
> button {
|
||||
//margin-top: -2px;
|
||||
//float: left;
|
||||
@@ -29,7 +29,7 @@
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
|
||||
|
||||
.msp-overlay-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -40,7 +40,7 @@
|
||||
//background: black;
|
||||
//opacity: 0.5;
|
||||
}
|
||||
|
||||
|
||||
.msp-overlay-content-wrap {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -51,37 +51,37 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.msp-overlay-content {
|
||||
text-align: center;
|
||||
|
||||
> div {
|
||||
|
||||
text-align: center;
|
||||
|
||||
> div {
|
||||
|
||||
padding-top: 2 * $row-height;
|
||||
|
||||
.msp-task-state {
|
||||
|
||||
.msp-task-state {
|
||||
$size: $row-height;
|
||||
text-align: center;
|
||||
|
||||
|
||||
> div {
|
||||
height: $size;
|
||||
margin-top: $control-spacing;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
|
||||
> div {
|
||||
height: $size;
|
||||
line-height: $size;
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
background: $default-background;
|
||||
padding: 0 ($control-spacing);
|
||||
font-weight: bold;
|
||||
@include non-selectable;
|
||||
}
|
||||
|
||||
|
||||
> button {
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
margin-top: -3px;
|
||||
font-size: 140%;
|
||||
}
|
||||
@@ -94,39 +94,41 @@
|
||||
/* background */
|
||||
|
||||
.msp-background-tasks {
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
|
||||
.msp-task-state {
|
||||
|
||||
.msp-task-state {
|
||||
$size: $row-height;
|
||||
|
||||
|
||||
> div {
|
||||
height: $size;
|
||||
margin-top: 1px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background: $default-background;
|
||||
|
||||
|
||||
> div {
|
||||
height: $size;
|
||||
line-height: $size;
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
padding: 0 ($control-spacing);
|
||||
@include non-selectable;
|
||||
white-space: nowrap;
|
||||
background: $default-background;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
> button {
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
margin-top: -3px;
|
||||
font-size: 140%;
|
||||
// font-size: 140%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .msp-background-tasks .msp-task-state {
|
||||
// color:
|
||||
// color:
|
||||
// }
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
height: $row-height;
|
||||
|
||||
text-align-last: center;
|
||||
background: none !important;
|
||||
background: none;
|
||||
padding: 0 $control-spacing;
|
||||
|
||||
> option[value = _] {
|
||||
@@ -187,7 +187,6 @@
|
||||
position: absolute;
|
||||
left: $control-spacing;
|
||||
top: $control-spacing;
|
||||
z-index: 10000;
|
||||
|
||||
.msp-traj-controls {
|
||||
line-height: $row-height;
|
||||
|
||||
@@ -3,27 +3,39 @@
|
||||
|
||||
.msp-layout-standard-outside {
|
||||
position: absolute;
|
||||
@import 'layout/controls-outside';
|
||||
@import 'layout/controls-outside';
|
||||
}
|
||||
|
||||
.msp-layout-standard-landscape {
|
||||
position: absolute;
|
||||
@import 'layout/controls-landscape';
|
||||
@import 'layout/controls-landscape';
|
||||
}
|
||||
|
||||
.msp-layout-standard-portrait {
|
||||
position: absolute;
|
||||
@import 'layout/controls-portrait';
|
||||
@import 'layout/controls-portrait';
|
||||
}
|
||||
|
||||
.msp-layout-expanded {
|
||||
.msp-layout-standard-reactive {
|
||||
position: absolute;
|
||||
|
||||
@media (orientation:landscape), (min-width: 1000px) {
|
||||
@import 'layout/controls-landscape';
|
||||
};
|
||||
|
||||
@media (orientation:portrait) and (max-width: 1000px) {
|
||||
@import 'layout/controls-portrait';
|
||||
};
|
||||
}
|
||||
|
||||
.msp-layout-expanded {
|
||||
position: fixed;
|
||||
|
||||
|
||||
@media (orientation:landscape) {
|
||||
@import 'layout/controls-landscape';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@media (orientation:portrait) {
|
||||
@import 'layout/controls-portrait';
|
||||
} ;
|
||||
};
|
||||
}
|
||||
@@ -80,4 +80,5 @@ $entity-tag-color: color-lower-contrast($font-color, 20%);
|
||||
|
||||
// sequence
|
||||
$sequence-background: $default-background;
|
||||
$sequence-number-color: $hover-font-color;
|
||||
$sequence-select-width: 300px;
|
||||
@@ -199,7 +199,7 @@ const DownloadStructure = StateAction.build({
|
||||
createStructureTree(ctx, traj, supportProps)
|
||||
}
|
||||
}
|
||||
return state.updateTree(b);
|
||||
return state.updateTree(b, { revertIfAborted: true });
|
||||
});
|
||||
|
||||
function getDownloadParams(src: string, url: (id: string) => string, label: (id: string) => string, isBinary: boolean): StateTransformer.Params<Download>[] {
|
||||
|
||||
@@ -8,11 +8,14 @@ import { Structure } from '../../../mol-model/structure';
|
||||
import { ComputedSecondaryStructure } from '../../../mol-model-props/computed/secondary-structure';
|
||||
|
||||
/**
|
||||
* Attaches ComputedSecondaryStructure property when unavailable in sourceData
|
||||
* Attaches ComputedSecondaryStructure property when unavailable in sourceData and
|
||||
* when not an archival file (i.e. no database_2.database_id field)
|
||||
*/
|
||||
export async function ensureSecondaryStructure(s: Structure) {
|
||||
if (s.models.length === 1 && s.model && s.model.sourceData.kind === 'mmCIF') {
|
||||
if (!s.model.sourceData.data.struct_conf.id.isDefined && !s.model.sourceData.data.struct_sheet_range.id.isDefined) {
|
||||
if (!s.model.sourceData.data.struct_conf.id.isDefined && !s.model.sourceData.data.struct_sheet_range.id.isDefined &&
|
||||
!s.model.sourceData.data.database_2.database_id.isDefined
|
||||
) {
|
||||
await ComputedSecondaryStructure.attachFromCifOrCompute(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import { ensureSecondaryStructure } from './helpers';
|
||||
import { Script } from '../../../mol-script/script';
|
||||
import { parse3DG } from '../../../mol-io/reader/3dg/parser';
|
||||
import { trajectoryFrom3DG } from '../../../mol-model-formats/structure/3dg';
|
||||
import { CompiledStructureSelectionQueries } from '../../util/structure-selection-helper';
|
||||
import { StructureSelectionQueries } from '../../util/structure-selection-helper';
|
||||
|
||||
export { TrajectoryFromBlob };
|
||||
export { TrajectoryFromMmCif };
|
||||
@@ -564,18 +564,18 @@ const StructureComplexElement = PluginStateTransform.BuiltIn({
|
||||
|
||||
let query: StructureQuery, label: string;
|
||||
switch (params.type) {
|
||||
case 'protein-and-nucleic': query = CompiledStructureSelectionQueries.proteinAndNucleic; label = 'Sequence'; break;
|
||||
case 'protein-and-nucleic': query = StructureSelectionQueries.proteinAndNucleic.query; label = 'Sequence'; break;
|
||||
|
||||
case 'protein': query = CompiledStructureSelectionQueries.protein; label = 'Protein'; break;
|
||||
case 'nucleic': query = CompiledStructureSelectionQueries.nucleic; label = 'Nucleic'; break;
|
||||
case 'protein': query = StructureSelectionQueries.protein.query; label = 'Protein'; break;
|
||||
case 'nucleic': query = StructureSelectionQueries.nucleic.query; label = 'Nucleic'; break;
|
||||
case 'water': query = Queries.internal.water(); label = 'Water'; break;
|
||||
|
||||
case 'branched': query = CompiledStructureSelectionQueries.branchedPlusConnected; label = 'Branched'; break;
|
||||
case 'ligand': query = CompiledStructureSelectionQueries.ligandPlusConnected; label = 'Ligand'; break;
|
||||
case 'branched': query = StructureSelectionQueries.branchedPlusConnected.query; label = 'Branched'; break;
|
||||
case 'ligand': query = StructureSelectionQueries.ligandPlusConnected.query; label = 'Ligand'; break;
|
||||
|
||||
case 'modified': query = CompiledStructureSelectionQueries.modified; label = 'Modified'; break;
|
||||
case 'modified': query = StructureSelectionQueries.modified.query; label = 'Modified'; break;
|
||||
|
||||
case 'coarse': query = CompiledStructureSelectionQueries.coarse; label = 'Coarse'; break;
|
||||
case 'coarse': query = StructureSelectionQueries.coarse.query; label = 'Coarse'; break;
|
||||
|
||||
case 'atomic-sequence': query = Queries.internal.atomicSequence(); label = 'Sequence'; break;
|
||||
case 'atomic-het': query = Queries.internal.atomicHet(); label = 'HET Groups/Ligands'; break;
|
||||
|
||||
@@ -32,6 +32,7 @@ import { Transparency } from '../../../mol-theme/transparency';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
import { Script } from '../../../mol-script/script';
|
||||
import { getUnitcellRepresentation, UnitcellParams } from '../../util/model-unitcell';
|
||||
import { getStructureOrientationRepresentation, OrientationParams } from '../../util/structure-orientation';
|
||||
|
||||
export { StructureRepresentation3D }
|
||||
export { StructureRepresentation3DHelpers }
|
||||
@@ -61,9 +62,9 @@ namespace StructureRepresentation3DHelpers {
|
||||
|
||||
export function createParams<R extends RepresentationProvider<Structure, any, any>, C extends ColorTheme.Provider<any>, S extends SizeTheme.Provider<any>>(
|
||||
ctx: PluginContext, structure: Structure, params: {
|
||||
repr?: R | [R, (r: R, ctx: ThemeRegistryContext, s: Structure) => RepresentationProvider.ParamValues<R>],
|
||||
color?: C | [C, (c: C, ctx: ThemeRegistryContext) => ColorTheme.ParamValues<C>],
|
||||
size?: S | [S, (c: S, ctx: ThemeRegistryContext) => SizeTheme.ParamValues<S>]
|
||||
repr?: R | [R, (r: R, ctx: ThemeRegistryContext, s: Structure) => Partial<RepresentationProvider.ParamValues<R>>],
|
||||
color?: C | [C, (c: C, ctx: ThemeRegistryContext) => Partial<ColorTheme.ParamValues<C>>],
|
||||
size?: S | [S, (c: S, ctx: ThemeRegistryContext) => Partial<SizeTheme.ParamValues<S>>]
|
||||
}): StateTransformer.Params<StructureRepresentation3D> {
|
||||
|
||||
const themeCtx = ctx.structureRepresentation.themeCtx
|
||||
@@ -79,16 +80,18 @@ namespace StructureRepresentation3DHelpers {
|
||||
const color = params.color
|
||||
? params.color instanceof Array ? params.color[0] : params.color
|
||||
: themeCtx.colorThemeRegistry.get(repr.defaultColorTheme);
|
||||
const colorDefaultParams = PD.getDefaultValues(color.getParams(themeCtx))
|
||||
const colorParams = params.color instanceof Array
|
||||
? params.color[1](color as C, themeCtx)
|
||||
: PD.getDefaultValues(color.getParams(themeCtx));
|
||||
? { ...colorDefaultParams, ...params.color[1](color as C, themeCtx) }
|
||||
: colorDefaultParams;
|
||||
|
||||
const size = params.size
|
||||
? params.size instanceof Array ? params.size[0] : params.size
|
||||
: themeCtx.sizeThemeRegistry.get(repr.defaultSizeTheme);
|
||||
const sizeDefaultParams = PD.getDefaultValues(size.getParams(themeCtx))
|
||||
const sizeParams = params.size instanceof Array
|
||||
? params.size[1](size as S, themeCtx)
|
||||
: PD.getDefaultValues(size.getParams(themeCtx));
|
||||
? { ...sizeDefaultParams, ...params.size[1](size as S, themeCtx) }
|
||||
: sizeDefaultParams;
|
||||
|
||||
return ({
|
||||
type: { name: ctx.structureRepresentation.registry.getName(repr), params: reprParams },
|
||||
@@ -696,4 +699,32 @@ const ModelUnitcell3D = PluginStateTransform.BuiltIn({
|
||||
return StateTransformer.UpdateResult.Updated;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export { StructureOrientation3D }
|
||||
type StructureOrientation3D = typeof StructureOrientation3D
|
||||
const StructureOrientation3D = PluginStateTransform.BuiltIn({
|
||||
name: 'structure-orientation-3d',
|
||||
display: 'Structure Orientation',
|
||||
from: SO.Molecule.Structure,
|
||||
to: SO.Shape.Representation3D,
|
||||
params: {
|
||||
...OrientationParams,
|
||||
}
|
||||
})({
|
||||
canAutoUpdate({ oldParams, newParams }) {
|
||||
return true;
|
||||
},
|
||||
apply({ a, params }) {
|
||||
return Task.create('Structure Orientation', async ctx => {
|
||||
const repr = await getStructureOrientationRepresentation(ctx, a.data, params);
|
||||
return new SO.Shape.Representation3D({ repr, source: a }, { label: `Orientation` });
|
||||
});
|
||||
},
|
||||
update({ a, b, newParams }) {
|
||||
return Task.create('Structure Orientation', async ctx => {
|
||||
await getStructureOrientationRepresentation(ctx, a.data, newParams, b.data.repr as ShapeRepresentation<any, any, any>);
|
||||
return StateTransformer.UpdateResult.Updated;
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -84,7 +84,7 @@ export abstract class CollapsableControls<P extends CollapsableProps = Collapsab
|
||||
|
||||
return <div className={wrapClass}>
|
||||
<div className='msp-transform-header'>
|
||||
<button className='msp-btn msp-btn-block' onClick={this.toggleCollapsed}>
|
||||
<button className='msp-btn msp-btn-block msp-btn-collapse' onClick={this.toggleCollapsed}>
|
||||
<span className={`msp-icon msp-icon-${this.state.isCollapsed ? 'expand' : 'collapse'}`} />
|
||||
{this.state.header}
|
||||
</button>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user