Compare commits

...

184 Commits

Author SHA1 Message Date
Alexander Rose
5d9e14aad1 0.4.2 2019-11-19 15:29:19 -08:00
Alexander Rose
9963cb3770 prevent browser scrolling with middle click (FF on win) 2019-11-19 09:02:20 -08:00
Alexander Rose
5731ef20b3 0.4.1 2019-11-18 16:14:41 -08:00
Alexander Rose
ab89d34440 package updates 2019-11-18 16:13:43 -08:00
Alexander Rose
d9bac2916c fix polymer sequence widget .getLoci
was not taking operator.name into account
2019-11-18 15:21:42 -08:00
Alexander Rose
edaa9610f6 camera focus takes granularity into account 2019-11-18 14:39:32 -08:00
Alexander Rose
90255b1a1b moved loci normalization/granularity to model/loci 2019-11-18 14:38:55 -08:00
Alexander Rose
639f137ad2 fix PrincipalAxes 2019-11-18 12:08:53 -08:00
Alexander Rose
29609e04c2 improved structure docs and sequence description 2019-11-18 11:43:51 -08:00
Alexander Rose
736aaf4433 matrix and axes improvements 2019-11-18 11:43:10 -08:00
Alexander Rose
2d7248962f add oriented-box visual to structure-orientation 2019-11-17 19:02:44 -08:00
Alexander Rose
a13c98c36c fix StructureElementSelectionManager.getPrincipalAxes for multiple entries 2019-11-17 17:32:37 -08:00
Alexander Rose
e298499326 improved handling of Structure.Loci, added whole structure support to Stats 2019-11-17 17:27:57 -08:00
Alexander Rose
6e1e463e1d fix whole structure selection/highlighting 2019-11-17 16:45:16 -08:00
Alexander Rose
2a2261beaf principal axes for loci and orientation for Camera.focus 2019-11-17 16:10:28 -08:00
Alexander Rose
14623f5df2 vec3 improvements, .matchDirection & readonly .negUnit 2019-11-17 16:03:48 -08:00
Alexander Rose
32889779a2 ModelUnitcell cleanup 2019-11-16 19:22:06 -08:00
Alexander Rose
911a7e3636 wip, structure orientation representation 2019-11-16 19:21:37 -08:00
Alexander Rose
bcf8ae2734 wip, principal component refactoring 2019-11-16 19:20:40 -08:00
Alexander Rose
92df3b1f42 console.log 2019-11-16 16:11:53 -08:00
Alexander Rose
5bbed1f9a3 remove console.log statement 2019-11-16 16:10:46 -08:00
Alexander Rose
0a391760b8 fix stats.firstResidueLoc assignment 2019-11-16 15:42:12 -08:00
Alexander Rose
e7eeb8cb55 center/focus with left+alt 2019-11-16 14:46:06 -08:00
Alexander Rose
bee4f38209 0.4.0 2019-11-15 16:35:56 -08:00
Alexander Rose
ff4dcfc220 package updates 2019-11-15 16:34:13 -08:00
Alexander Rose
ad726a97e4 filter display list of select queries, add bonded query 2019-11-15 16:12:49 -08:00
Alexander Rose
b533542792 check if pointer actually moved 2019-11-15 15:15:09 -08:00
Alexander Rose
dbe33cc046 twekaed mouse bindings
left: toggle selection
middle: center
right: show surrounding
2019-11-15 15:06:59 -08:00
Alexander Rose
3ddf5f4bec tweaked StructureRepresentationInteraction visual
make look less like ball+stick default
2019-11-15 15:04:46 -08:00
Alexander Rose
f02d49f181 typo 2019-11-15 15:01:57 -08:00
Alexander Rose
4df68697f2 update CommonSaccharideNames 2019-11-15 15:01:36 -08:00
Alexander Rose
eeb09d9184 allow partial params in .createParams helper 2019-11-15 15:01:17 -08:00
David Sehnal
d8509a145b mol-model: fixed Loci stats 2019-11-15 21:01:38 +01:00
David Sehnal
e3cb799638 mol-model: fix Loci.extentTo* 2019-11-15 20:49:59 +01:00
David Sehnal
ce9469c85b mol-model: Fixed Loci.isSubset 2019-11-15 20:33:08 +01:00
David Sehnal
e62b166805 mol-model: fix Loci Stats.add 2019-11-15 20:12:47 +01:00
David Sehnal
a1f283c641 Merge branch 'master' of https://github.com/molstar/molstar 2019-11-15 20:05:49 +01:00
David Sehnal
2b14c398a8 mol-model: optimized Loci.extendToResidues/Chains 2019-11-15 20:05:44 +01:00
Alexander Rose
d8480d058b don't apply granularity for State Highlight 2019-11-15 09:51:51 -08:00
David Sehnal
b1ac1a36d4 mol-model: extendToWholeChains now works on partitioned chains 2019-11-15 16:27:58 +01:00
David Sehnal
3c2d014ad3 mol-model: count chains in Loci stats 2019-11-15 14:39:17 +01:00
David Sehnal
d940d26312 mol-model: added Unit.Traits (replaces multiChain prop) 2019-11-15 13:23:01 +01:00
Alexander Rose
99028b5c99 use unit.chainGroupId in sequence widget 2019-11-14 18:03:26 -08:00
Alexander Rose
ac94f0659d add unit.multiChain; tweaks to unit.chainGroupId 2019-11-14 18:03:03 -08:00
Alexander Rose
bd85a5a153 sequence widget help icon 2019-11-14 14:57:21 -08:00
Alexander Rose
9aa375a45f handle conformations in selections, marking, labels 2019-11-14 14:16:26 -08:00
David Sehnal
999cb99eb8 mol-data: fixed bug in isSubsetIS 2019-11-14 06:09:30 +01:00
Alexander Rose
12b53bc4bb added failing unittest for isSubsetIS 2019-11-13 18:21:20 -08:00
Alexander Rose
952f3c451f package updates, removed now superfluous @types/webgl2 2019-11-13 13:49:50 -08:00
David Sehnal
ce06375a92 mol-plugin: sequence view remove scrollTo behavior 2019-11-13 16:19:59 +01:00
Alexander Rose
c0f60d48bb tweaked label/description for custom volume param.isRelative 2019-11-12 17:12:54 -08:00
Alexander Rose
e40f08d467 update packages 2019-11-12 17:00:44 -08:00
Alexander Rose
9c977bf90f add ColorSwatch and use instead of ColorNames for color dropdown 2019-11-12 17:00:30 -08:00
Alexander Rose
525f32feab use elementLabel() for sequence widget dropdown 2019-11-12 16:04:13 -08:00
Alexander Rose
cdb698f0d1 added stripTags string helper 2019-11-12 16:03:38 -08:00
Alexander Rose
c65d09f4a8 use previous SequenceView.state when structure hasn't changed 2019-11-12 15:13:13 -08:00
Alexander Rose
7d4e48431c add e.stopPropagation(); to onKeyPress methods in controls 2019-11-12 14:42:36 -08:00
Alexander Rose
6a7268a9c9 improved sequenceNumberPeriod for short sequences 2019-11-12 12:03:30 -08:00
Alexander Rose
eea1137abc prefer EMDB map for 'ELECTRON CRYSTALLOGRAPHY' entries 2019-11-12 11:44:46 -08:00
Alexander Rose
a130121698 fix extra layout(location = X) definitions in shaders 2019-11-12 10:39:46 -08:00
Alexander Rose
153f039ee6 added number-parser spec 2019-11-08 21:23:02 -05:00
Alexander Rose
b7216d28f4 wip, cif-core support 2019-11-08 21:12:01 -05:00
David Sehnal
ee34139094 added setMolStarDebugMode 2019-11-07 17:23:42 +01:00
David Sehnal
9addea79b7 updated packages 2019-11-07 16:56:58 +01:00
Alexander Rose
2c88ace91c added number precision helpers, improved isovalue step calculation 2019-11-05 06:14:35 +03:00
David Sehnal
6eae95f964 mol-plugin: scroll first highlighted/selected element into view 2019-11-02 15:48:20 +01:00
David Sehnal
b44ed7c45a mol-theme: lociLabel tweaks 2019-11-02 15:33:14 +01:00
David Sehnal
b2d2546e39 mol-model: added chainGroupId 2019-11-02 14:58:29 +01:00
David Sehnal
4dbabdf350 mol-plugin: fix SubstructureParentHelper 2019-11-02 13:13:31 +01:00
David Sehnal
df63d8fe0f mol-plugin: support HTML tags in labels, tweaks to default label provider 2019-11-02 12:15:17 +01:00
David Sehnal
c9116575fa mol-model: support isConnectedTo query disjunct and invert 2019-11-02 11:34:46 +01:00
David Sehnal
6707673c7f mol-model: fixes to link related queries 2019-11-02 11:30:02 +01:00
Alexander Rose
1f82446843 0.3.12 2019-11-01 13:43:17 -07:00
Alexander Rose
9942b0e389 avoid extra selection in cellpack loader 2019-11-01 13:41:39 -07:00
Alexander Rose
f57e8501c4 fix order in LociMarkManager.normalizedLoci 2019-11-01 13:25:14 -07:00
Alexander Rose
1e9fa003db don't apply granularity in StructureSelectionControls 2019-11-01 11:29:58 -07:00
Alexander Rose
7868b22918 added disulfide-bridges StructureSelectionQuery 2019-11-01 11:15:40 -07:00
Alexander Rose
e2c80956dc structureElementStatsLabel tweaks 2019-11-01 11:12:48 -07:00
David Sehnal
5d5af58bdf mol-model: removed QueryContextLinkInfo.swap 2019-11-01 16:47:23 +01:00
David Sehnal
8f78106816 mol-data: fix SortedArray.union & mol-model: fix includeConnected 2019-11-01 15:43:04 +01:00
David Sehnal
1923289c51 mol-plugin: better element loci highlight label 2019-11-01 14:55:37 +01:00
David Sehnal
14c22147d5 mol-script: added linkedAtomicPairs generator + fixed assembly-symmetry-axes isApplicable for empty structures 2019-11-01 14:39:15 +01:00
David Sehnal
6d39bc4a20 mol-script: added more link props, support different element reference for atomic props 2019-11-01 13:46:40 +01:00
Alexander Rose
cfaecb590d fix StructureRepresentationInteractionBehavior bundle handling 2019-10-31 19:05:51 -07:00
Alexander Rose
2894c18ba1 0.3.11 2019-10-31 17:13:11 -07:00
Alexander Rose
e6633c2fc6 optimized Bundle.toStructure 2019-10-31 17:10:47 -07:00
Alexander Rose
fe341f0851 fix Bundle.toStructure, #19 2019-10-31 16:55:04 -07:00
Alexander Rose
34a387d4bd optimize StructureRepresentationInteractionBehavior by using bundle 2019-10-31 12:35:49 -07:00
Alexander Rose
f975d9c8dc add names anon molql functions for debugging/profiling 2019-10-31 12:31:25 -07:00
Alexander Rose
563ff98c83 fix MolScript.internal.generator.bundle binding 2019-10-31 12:29:02 -07:00
Alexander Rose
0b9ecb76b9 tweaked ball&stick default size 2019-10-31 10:27:24 -07:00
Alexander Rose
b8de1de3a8 don't calc sec-struc for archival files 2019-10-31 10:22:05 -07:00
Alexander Rose
ac2f48684e updated cif schemas with more meta data fields 2019-10-31 10:18:43 -07:00
Alexander Rose
9928b17a76 fix, carb preset missing connected 2019-10-31 09:44:06 -07:00
Alexander Rose
723a6a1fbd gracefully handle errors when getting em map info 2019-10-30 18:05:44 -07:00
Alexander Rose
51ac75943d query preset tweaks 2019-10-30 17:37:10 -07:00
Alexander Rose
6bcb5eac71 adjust 'auto' quality 2019-10-30 16:30:36 -07:00
Alexander Rose
f2f1e355c2 molql, fix expandConnected 2019-10-30 16:30:08 -07:00
Alexander Rose
4cc0754f11 add isNonStandard atom prop, use polymer repr preset 2019-10-30 15:35:18 -07:00
Alexander Rose
cd30caa12d better align negative sequence numbers in ui 2019-10-30 10:48:19 -07:00
Alexander Rose
41bc74e543 add support for Beta and Gamma peptides 2019-10-30 10:26:35 -07:00
David Sehnal
96a908698d mol-data: fix Column.view if underlying __array is of different type than value 2019-10-30 12:21:29 +01:00
Alexander Rose
77a561024f removed unneccessary z-index 2019-10-29 16:24:47 -07:00
Alexander Rose
5d0176e686 use landscape for reactive layout when width > 1000 2019-10-29 15:41:23 -07:00
David Sehnal
3a6013145e mol-task: fixed subtask cancellation 2019-10-29 21:42:26 +01:00
David Sehnal
c5e2471f34 mol-state/task: use console.error only when not in production mode 2019-10-29 20:37:29 +01:00
Alexander Rose
e9802f2191 0.3.10 2019-10-29 12:07:55 -07:00
Alexander Rose
2d0097fddc package updates 2019-10-29 12:07:02 -07:00
Alexander Rose
1a245db4c9 tweaked bindings formating 2019-10-29 11:56:38 -07:00
Alexander Rose
6a694f9298 wip, tweak tasks css 2019-10-28 17:25:11 -07:00
Alexander Rose
acd1f43018 0.3.9 2019-10-28 16:57:41 -07:00
Alexander Rose
71ed9a2db9 fix extractCrossLinkRestraints 2019-10-28 16:51:21 -07:00
David Sehnal
2b5d9bd213 Merge branch 'master' of https://github.com/molstar/molstar 2019-10-28 22:13:30 +01:00
David Sehnal
32c8664829 mol-plugin: fix transform update UI when error happens 2019-10-28 22:13:10 +01:00
David Sehnal
26e6e0ab72 Task cancellation fix 2019-10-28 22:03:10 +01:00
Alexander Rose
6d9c9bd884 use model.entryId(s) for image filename when possible 2019-10-28 12:07:30 -07:00
David Sehnal
2a74d5eb94 mol-state: added revertible update (and used it in DownloadStrucutre action) 2019-10-28 16:23:41 +01:00
David Sehnal
04d39e0e8d support Task cancellation in plugin UI 2019-10-28 16:01:13 +01:00
David Sehnal
c5e64b39db mol-model-formats: mmCIF substitute undefined atom_site.label_* with auth_* columns (and vice versa) 2019-10-27 11:53:37 +01:00
Alexander Rose
4911585a85 fix seq number in sequence widget for atomic models without auth_seq_id 2019-10-25 18:26:08 -07:00
Alexander Rose
590c00114f 0.3.8 2019-10-25 15:48:20 -07:00
Alexander Rose
111eded34a disable some ui elements when state tree is busy 2019-10-25 12:18:46 -07:00
Alexander Rose
d767900fb1 fix, canvas.render not always returning true when it did render 2019-10-25 12:06:14 -07:00
Alexander Rose
9074d5390a add support for sequence numbers in coarse units 2019-10-24 16:28:06 -07:00
Alexander Rose
91027459ca typos 2019-10-24 15:02:23 -07:00
Alexander Rose
a2eda6c5af added controls display options: outside, portrait, landscape, reactive 2019-10-24 11:32:00 -07:00
Alexander Rose
338489febd 0.3.7 2019-10-24 07:54:31 -07:00
David Sehnal
94e7820baf mol-data: SortedArray fix 2019-10-24 07:40:35 +02:00
Alexander Rose
a47df57709 more SortedArray.union tests (one failing) 2019-10-23 19:32:41 -07:00
Alexander Rose
f73d64f732 0.3.6 2019-10-23 18:15:46 -07:00
Alexander Rose
cfaef4c567 added more volume param docs 2019-10-23 18:14:16 -07:00
Alexander Rose
3ec2c6ded4 ui layout tweaks 2019-10-23 17:18:16 -07:00
Alexander Rose
2afaa35170 increased default wireframe thickness from 1 to 1.5 2019-10-23 17:17:34 -07:00
Alexander Rose
efcf4a77c6 add molecular surface wireframe visual 2019-10-23 17:16:40 -07:00
Alexander Rose
221e1de4e7 improved entity-source color theme 2019-10-23 12:25:59 -07:00
Alexander Rose
f2de2983c8 added isInteger helper 2019-10-23 12:25:38 -07:00
Alexander Rose
82c8499789 updated cif schemas 2019-10-23 11:43:19 -07:00
David Sehnal
d66ccdb255 mol-plugin: sequence view tweaks 2019-10-23 09:27:59 +02:00
David Sehnal
8d13c514b0 mol-data: SortedArray fix 2019-10-23 09:17:25 +02:00
Alexander Rose
f57aafba19 improved sequence numbers in sequence widget UI 2019-10-22 17:25:57 -07:00
Alexander Rose
0a7406db15 added more SortedArray.union tests, one failing 2019-10-22 15:17:18 -07:00
Alexander Rose
2f97e8b329 overset residue numbers in sequence ui 2019-10-22 12:24:53 -07:00
David Sehnal
22a8758852 mol-data: fixed SortedArray.union 2019-10-22 20:48:16 +02:00
Alexander Rose
bc6bc1d57a fix StructureElement.Stats 2019-10-22 10:22:02 -07:00
Alexander Rose
4a692b9a88 ensure applicable repr types are up-to-date 2019-10-22 10:20:55 -07:00
Alexander Rose
0094f800dc fixed entity-source color theme labels 2019-10-21 18:18:26 -07:00
Alexander Rose
9bd616f36f ensure file extension for image download 2019-10-21 17:59:09 -07:00
David Sehnal
4acc36628d mol-plugin: show sequence offsets in UI (wip) 2019-10-21 15:06:58 +02:00
David Sehnal
e550413778 mol-state: added createDefaultParams to StateAction and StateTransformer 2019-10-21 13:45:18 +02:00
David Sehnal
ccdc894979 ability to set default params for volume streaming 2019-10-21 13:39:05 +02:00
David Sehnal
322bc71d52 changed default color list to dark-2 to avoid a clash with EM volume map colors 2019-10-21 12:49:04 +02:00
Alexander Rose
7c55e4d234 0.3.5 2019-10-18 17:02:14 -07:00
Alexander Rose
8c8058290c fixed spacegroup index/number handling 2019-10-18 16:58:53 -07:00
David Sehnal
9d413bf0eb mol-util: palette fix missing valueLabel function 2019-10-18 15:29:45 +02:00
Alexander Rose
8fde5dd1bf 0.3.4 2019-10-17 11:47:10 -07:00
Alexander Rose
2f9ecb9396 package updates 2019-10-17 11:46:26 -07:00
Alexander Rose
85092279fa better handle unsupported extensions 2019-10-17 11:40:32 -07:00
Alexander Rose
d0189523e4 fix Loci stats for partial residue selections 2019-10-17 11:10:10 -07:00
Alexander Rose
a26d03205a tweak bindings to work better with one-button mouse 2019-10-16 18:26:22 -07:00
Alexander Rose
862eda6dd4 better min size limit in image ui 2019-10-16 17:54:46 -07:00
Alexander Rose
4a7f0fc206 hide non-applicable repr types in repr ui 2019-10-16 17:46:27 -07:00
Alexander Rose
6bbee58d39 guard against undefined values in ParameterControls 2019-10-16 16:42:14 -07:00
Alexander Rose
989faed410 added StructureSelectionQuery wrapping expr & query 2019-10-16 16:30:38 -07:00
Alexander Rose
198e2f2043 support for currentSelection in StructureSelectionHelper and surroundings query 2019-10-16 15:48:39 -07:00
Alexander Rose
6ae3d4110d added StructureElement.Loci.toStructure 2019-10-16 15:47:57 -07:00
David Sehnal
c34e1be43b Merge branch 'master' of https://github.com/molstar/molstar 2019-10-16 20:46:40 +02:00
David Sehnal
17a440ad9c moved StructureQuery.runExpr to Script.getStructureSelection to fix cyclic dep 2019-10-16 20:46:25 +02:00
Alexander Rose
04dcfc7adb check seqId compatibility for cyclic peptides 2019-10-16 11:01:07 -07:00
David Sehnal
ca66e334c1 mol-model: added StructureQuery.runExpr 2019-10-16 13:47:06 +02:00
David Sehnal
54bba4c92f mol-script: added internal.generator.current symbol 2019-10-16 13:38:58 +02:00
David Sehnal
9c046b808c mol-script: added Bundle support 2019-10-16 13:26:05 +02:00
David Sehnal
ca5d1865cc mol-model: Loci fixes 2019-10-16 12:48:21 +02:00
Alexander Rose
d8f1aa5bc9 support for streaming multiple em volumes, limit to associate maps 2019-10-15 17:38:42 -07:00
David Sehnal
6ac790e083 mol-model: renamed StructureSelection.toLoci* 2019-10-15 08:49:06 +02:00
David Sehnal
d0870e4bbb added highlight example to basic wrapper, better empty loci handling 2019-10-15 08:44:50 +02:00
Alexander Rose
5138595f36 added more StructureSelectionQueries 2019-10-14 16:26:54 -07:00
Alexander Rose
d9aa5684a9 show non-polymer residues of polymer entities as ball&stick 2019-10-14 14:09:34 -07:00
Alexander Rose
8e2521a7a9 consider coarse/non-coarse backbone when checking distance for backbone links 2019-10-14 14:09:12 -07:00
Alexander Rose
7dd7a117cb wip, terminal gaps 2019-10-11 16:55:39 -07:00
Alexander Rose
defbadf4d7 handle polymer ends in visuals properly 2019-10-11 16:55:22 -07:00
Alexander Rose
131e88080a 0.3.3 2019-10-10 10:43:52 -07:00
Alexander Rose
fb78b886c1 collapse link labels to hide repeated ids 2019-10-10 10:41:56 -07:00
Alexander Rose
aed0b87b16 fix fractional canvas/image dimensions 2019-10-10 10:35:44 -07:00
Alexander Rose
1316cc6a40 fix StructureSelectionControls.focus for single element 2019-10-09 17:52:59 -07:00
180 changed files with 6252 additions and 1922 deletions

View File

@@ -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
View 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
1 audit.block_doi
2 database_code.depnum_ccdc_archive
3 chemical.name_systematic
4 chemical.name_common
5 chemical.melting_point
6 chemical_formula.moiety
7 chemical_formula.sum
8 chemical_formula.weight
9 atom_type.symbol
10 atom_type.description
11 atom_type_scat.dispersion_real
12 atom_type_scat.dispersion_imag
13 atom_type_scat.source
14 space_group.crystal_system
15 space_group.name_H-M_full
16 space_group_symop.operation_xyz
17 cell.length_a
18 cell.length_b
19 cell.length_c
20 cell.angle_alpha
21 cell.angle_beta
22 cell.angle_gamma
23 cell.volume
24 cell.formula_units_Z
25 atom_site.label
26 atom_site.type_symbol
27 atom_site.fract_x
28 atom_site.fract_y
29 atom_site.fract_z
30 atom_site.U_iso_or_equiv
31 atom_site.adp_type
32 atom_site.occupancy
33 atom_site.calc_flag
34 atom_site.refinement_flags
35 atom_site.disorder_assembly
36 atom_site.disorder_group
37 atom_site.site_symmetry_multiplicity
38 atom_site_aniso.label
39 atom_site_aniso.U_11
40 atom_site_aniso.U_22
41 atom_site_aniso.U_33
42 atom_site_aniso.U_23
43 atom_site_aniso.U_13
44 atom_site_aniso.U_12
45 geom_bond.atom_site_label_1
46 geom_bond.atom_site_label_2
47 geom_bond.distance
48 geom_bond.site_symmetry_2
49 geom_bond.publ_flag

884
examples/867861-core.cif Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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"
}

View File

@@ -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());

View File

@@ -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;

View File

@@ -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();

View File

@@ -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),

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -202,7 +202,7 @@ namespace Canvas3D {
didRender = true
}
return didRender && cameraChanged;
return didRender;
}
let forceNextDraw = false;

View File

@@ -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,
}

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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 }

View File

@@ -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);

View File

@@ -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);
})
});

View File

@@ -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) {

View File

@@ -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];

View File

@@ -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)
}

View File

@@ -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))

View File

@@ -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}`,

View File

@@ -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

View File

@@ -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"')
}

View 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)
});
});

View File

@@ -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),
}
}

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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
*/

View File

@@ -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
*/

View 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> {}

View File

@@ -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

View File

@@ -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));

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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[]

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
}
}

View 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)
});
});

View File

@@ -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}`

View File

@@ -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) {

View File

@@ -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 };
}

View File

@@ -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: {

View File

@@ -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;

View File

@@ -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
}
//

View File

@@ -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
}
}

View File

@@ -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 */

View 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

View File

@@ -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>,
}
}
}

View File

@@ -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) {

View File

@@ -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
}
/**

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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();
};
}

View File

@@ -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)]);
};
}

View File

@@ -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();

View File

@@ -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));
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)

View File

@@ -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 = [

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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
}
}

View File

@@ -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),

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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]]

View File

@@ -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)) {

View File

@@ -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

View File

@@ -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);
}
}
}
});

View File

@@ -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;

View File

@@ -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)})`
}
}

View File

@@ -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)

View File

@@ -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 } });

View File

@@ -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))
}
}
}

View File

@@ -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
}
}

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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);
});
}

View File

@@ -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();

View File

@@ -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),

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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:
// }

View File

@@ -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;

View File

@@ -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';
} ;
};
}

View File

@@ -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;

View File

@@ -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>[] {

View File

@@ -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)
}
}

View File

@@ -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;

View File

@@ -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;
});
}
});

View File

@@ -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