Compare commits

..

2 Commits

Author SHA1 Message Date
Alexander Rose
1203be103e 0.4.5 2019-11-25 16:30:48 -08:00
Alexander Rose
87b3f32dfa fix ajaxGet: handle case where download had finished before callback were registered 2019-11-25 16:29:02 -08:00
1369 changed files with 65071 additions and 196615 deletions

View File

@@ -1,3 +0,0 @@
node_modules/*
build/*
lib/*

View File

@@ -1,96 +0,0 @@
{
"env": {
"browser": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true
}
},
"rules": {
"indent": "off",
"arrow-parens": [
"off",
"as-needed"
],
"brace-style": "off",
"comma-spacing": "off",
"space-infix-ops": "error",
"comma-dangle": "off",
"eqeqeq": [
"error",
"smart"
],
"import/order": "off",
"no-eval": "warn",
"no-new-wrappers": "warn",
"no-trailing-spaces": "error",
"no-unsafe-finally": "warn",
"no-var": "error",
"spaced-comment": "error",
"semi": "warn",
"no-restricted-syntax": [
"error",
{
"selector": "ExportDefaultDeclaration",
"message": "Default exports are not allowed"
}
]
},
"overrides": [
{
"files": ["**/*.ts", "**/*.tsx"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["tsconfig.json", "tsconfig.commonjs.json"],
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/class-name-casing": "off",
"@typescript-eslint/indent": [
"error",
4
],
"@typescript-eslint/member-delimiter-style": [
"off",
{
"multiline": {
"delimiter": "none",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"@typescript-eslint/semi": [
"off",
null
],
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/brace-style": [
"error",
"1tbs", { "allowSingleLine": true }
],
"@typescript-eslint/comma-spacing": "error"
}
}
]
}

View File

@@ -1,18 +0,0 @@
on:
push:
pull_request:
jobs:
eslint:
name: eslint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: install node v12
uses: actions/setup-node@v1
with:
node-version: 12
- name: yarn install
run: yarn install
- name: eslint
uses: icrawl/action-eslint@v1

1
.gitignore vendored
View File

@@ -5,7 +5,6 @@ node_modules/
debug.log
npm-debug.log
tsconfig.tsbuildinfo
tsconfig.commonjs.tsbuildinfo
*.sublime-workspace
.idea

View File

@@ -1 +0,0 @@
tsconfig.commonjs.buildinfo

View File

@@ -14,5 +14,6 @@ before_install:
node_js:
- "12"
- "10"
- "8"
before_script:
- export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start

View File

@@ -4,8 +4,8 @@
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"dbaeumer.vscode-eslint",
"firsttris.vscode-jest-runner",
"ms-vscode.vscode-typescript-tslint-plugin",
"msjsdiag.debugger-for-chrome",
"slevesque.shader",
"stpn.vscode-graphql",

View File

@@ -6,7 +6,4 @@
"*.vert.ts": "glsl",
"*.gql.ts": "graphql"
},
"eslint.options": {
"ignorePattern": ["webpack.config.js", "scripts/*"],
}
}

14
.vscode/tasks.json vendored
View File

@@ -9,20 +9,6 @@
"problemMatcher": [
"$tsc"
]
},
{
"type": "npm",
"script": "build-tsc",
"problemMatcher": [
"$tsc"
]
},
{
"type": "npm",
"script": "watch",
"problemMatcher": [
"$tsc"
]
}
]
}

View File

@@ -5,7 +5,7 @@
# Mol*
The goal of **Mol\*** (*/'mol-star/*) is to provide a technology stack that will serve as a basis for the next-generation data delivery and analysis tools for macromolecular structure data. This is a collaboration between PDBe and RCSB PDB teams and the development will be open-source and available to anyone who wants to use it for developing visualization tools for macromolecular structure data available from [PDB](https://www.wwpdb.org/) and other institutions.
The goal of **Mol\*** (*/'mol-star/*) is to provide a technology stack that will serve as basis for the next-generation data delivery and analysis tools for macromolecular structure data. This is a collaboration between PDBe and RCSB PDB teams and the development will be open source and available to anyone who wants to use it for developing visualisation tools for macromolecular structure data available from [PDB](https://www.wwpdb.org/) and other institutions.
This particular project is the implementation of this technology (still under development).
@@ -16,32 +16,29 @@ This particular project is the implementation of this technology (still under de
The core of Mol* currently consists of these modules (see under `src/`):
- `mol-task` Computation abstraction with progress tracking and cancellation support.
- `mol-data` Collections (integer-based sets, interface to columns/tables, etc.)
- `mol-data` Collections (integer based sets, interface to columns/tables, etc.)
- `mol-math` Math related (loosely) algorithms and data structures.
- `mol-io` Parsing library. Each format is parsed into an interface that corresponds to the data stored by it. Support for common coordinate, experimental/map, and annotation data formats.
- `mol-model` Data structures and algorithms (such as querying) for representing molecular data (including coordinate, experimental/map, and annotation data).
- `mol-model-formats` Data format parsers for `mol-model`.
- `mol-model-props` Common "custom properties".
- `mol-script` A scripting language for creating representations/scenes and querying (includes the [MolQL query language](https://molql.github.io)).
- `mol-script` A scriting language for creating representations/scenes and querying (includes the [MolQL query language](https://molql.github.io)).
- `mol-geo` Creating (molecular) geometries.
- `mol-theme` Theming for structure, volume and shape representations.
- `mol-repr` Molecular representations for structures, volumes and shapes.
- `mol-gl` A wrapper around WebGL.
- `mol-canvas3d` A low-level 3d view component. Uses `mol-geo` to generate geometries.
- `mol-canvas3d` A low level 3d view component. Uses `mol-geo` to generate geometries.
- `mol-state` State representation tree with state saving and automatic updates.
- `mol-app` Components for building UIs.
- `mol-app` Components for builduing UIs.
- `mol-plugin` Allow to define modular Mol* plugin instances utilizing `mol-state` and `mol-canvas3d`.
- `mol-plugin-state` State transformations, builders, and managers.
- `mol-plugin-ui` React-based user interface for the Mol* plugin. Some components of the UI are usable outside the main plugin and can be integrated into 3rd party solutions.
- `mol-util` Useful things that do not fit elsewhere.
Moreover, the project contains the implementation of `servers`, including
Moreover, the project contains the imlementation of `servers`, including
- `servers/model` A tool for accessing coordinate and annotation data of molecular structures.
- `servers/volume` A tool for accessing volumetric experimental data related to molecular structures.
- `servers/plugin-state` A basic server to store Mol* Plugin states.
The project also contains performance tests (`perf-tests`), `examples`, and basic proof of concept `cli` apps (CIF to BinaryCIF converter and JSON domain annotation to CIF converter).
The project also contains performance tests (`perf-tests`), `examples`, and basic proof of concept `apps` (CIF to BinaryCIF converter and JSON domain annotation to CIF converter).
## Previous Work
This project builds on experience from previous solutions:
@@ -62,8 +59,6 @@ This project builds on experience from previous solutions:
### Build automatically on file save:
npm run watch
If working on just the viewer, ``npm run watch-viewer`` will provide shorter compile times.
### Build with debug mode enabled:
DEBUG=molstar npm run watch
@@ -89,29 +84,20 @@ and navigate to `build/viewer`
### Code generation
**CIF schemas**
Install CIFTools `npm install ciftools -g`
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/mmcif.ts -p mmCIF
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/ccd.ts -p CCD
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/bird.ts -p BIRD
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/cif-core.ts -p CifCore -aa
**Lipid names**
node lib/commonjs/cli/lipid-params -o src/mol-model/structure/model/types/lipids.ts
**Ion names**
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-ions.js src/mol-model/structure/model/types/ions.ts
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/mmcif.ts -p mmCIF
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/ccd.ts -p CCD
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/bird.ts -p BIRD
**GraphQL schemas**
node node_modules//@graphql-codegen/cli/bin -c src/extensions/rcsb/graphql/codegen.yml
node data/rcsb-graphql/codegen.js
### Other scripts
**Create chem comp bond table**
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-table.js build/data/ccb.bcif -b
export NODE_PATH="lib"; node --max-old-space-size=4096 lib/apps/chem-comp-bond/create-table.js build/data/ccb.bcif -b
**Test model server**
@@ -123,26 +109,22 @@ and navigate to `build/viewer`
**Convert any CIF to BinaryCIF**
node lib/servers/model/preprocess -i file.cif -ob file.bcif
node build/model-server/preprocess -i file.cif -ob file.bcif
To see all available commands, use ``node lib/servers/model/preprocess -h``.
Or
node lib/commonjs/cli/cif2bcif
To see all available commands, use ``node build/model-server/preprocess -h``.
## Development
### Installation
### Intallation
If node complains about a missing acorn peer dependency, run the following commands
If node complains about a missine acorn peer dependency, run the following commands
npm update acorn --depth 20
npm dedupe
### Editor
To get syntax highlighting for shader and graphql files add the following to Visual Code's settings files and make sure relevant extensions are installed in the editor.
To get syntax highlighting for shader and graphql files add the following to Visual Code's settings files and make sure relevant extanesions are installed in the editor.
"files.associations": {
"*.glsl.ts": "glsl",
@@ -154,7 +136,7 @@ To get syntax highlighting for shader and graphql files add the following to Vis
## Publish
### Prerelease
npm version prerelease # assumes the current version ends with '-dev.X'
npm version prerelease # asumes the current version ends with '-dev.X'
npm publish --tag next
### Release
@@ -176,5 +158,4 @@ Continually develop this prototype project. As individual modules become stable,
Funding sources include but are not limited to:
* [RCSB PDB](https://www.rcsb.org) funding by a grant [DBI-1338415; PI: SK Burley] from the NSF, the NIH, and the US DoE
* [PDBe, EMBL-EBI](https://pdbe.org)
* [CEITEC](https://www.ceitec.eu/)
* [EntosAI](https://www.entos.ai) (``alpha-orbitals`` extension)
* [CEITEC](https://www.ceitec.eu/)

View File

@@ -1,12 +1,6 @@
audit.block_doi
database_code.depnum_ccdc_archive
database_code.depnum_ccdc_fiz
database_code.ICSD
database_code.MDF
database_code.NBS
database_code.CSD
database_code.COD
chemical.name_systematic
chemical.name_common
@@ -25,7 +19,6 @@ atom_type_scat.source
space_group.crystal_system
space_group.name_H-M_full
space_group.IT_number
space_group_symop.operation_xyz
cell.length_a
@@ -49,28 +42,19 @@ atom_site.calc_flag
atom_site.refinement_flags
atom_site.disorder_assembly
atom_site.disorder_group
atom_site.site_symmetry_multiplicity
atom_site_aniso.label
atom_site_aniso.U
atom_site_aniso.U_11
atom_site_aniso.U_22
atom_site_aniso.U_33
atom_site_aniso.U_23
atom_site_aniso.U_13
atom_site_aniso.U_12
atom_site_aniso.U_su
atom_site_aniso.U_11_su
atom_site_aniso.U_22_su
atom_site_aniso.U_33_su
atom_site_aniso.U_23_su
atom_site_aniso.U_13_su
atom_site_aniso.U_12_su
geom_bond.atom_site_label_1
geom_bond.atom_site_label_2
geom_bond.distance
geom_bond.site_symmetry_1
geom_bond.site_symmetry_2
geom_bond.publ_flag
geom_bond.valence
geom_bond.publ_flag
1 audit.block_doi
2 database_code.depnum_ccdc_archive
3 database_code.depnum_ccdc_fiz chemical.name_systematic
database_code.ICSD
database_code.MDF
database_code.NBS
database_code.CSD
database_code.COD
chemical.name_systematic
4 chemical.name_common
5 chemical.melting_point
6 chemical_formula.moiety
19 cell.length_b cell.length_c
20 cell.length_c cell.angle_alpha
21 cell.angle_alpha cell.angle_beta
cell.angle_beta
22 cell.angle_gamma
23 cell.volume
24 cell.formula_units_Z
42 atom_site_aniso.U_33 atom_site_aniso.U_23
43 atom_site_aniso.U_23 atom_site_aniso.U_13
44 atom_site_aniso.U_13 atom_site_aniso.U_12
45 geom_bond.atom_site_label_1
46 atom_site_aniso.U_12 geom_bond.atom_site_label_2
47 atom_site_aniso.U_su geom_bond.distance
48 atom_site_aniso.U_11_su geom_bond.site_symmetry_2
atom_site_aniso.U_22_su
49 atom_site_aniso.U_33_su geom_bond.publ_flag
50
51
52
53
54
geom_bond.distance
geom_bond.site_symmetry_1
geom_bond.site_symmetry_2
geom_bond.publ_flag
geom_bond.valence
55
56
57
58
59
60

View File

@@ -1,88 +0,0 @@
pdbx_reference_molecule.prd_id
pdbx_reference_molecule.name
pdbx_reference_molecule.represent_as
pdbx_reference_molecule.type
pdbx_reference_molecule.type_evidence_code
pdbx_reference_molecule.class
pdbx_reference_molecule.class_evidence_code
pdbx_reference_molecule.formula
pdbx_reference_molecule.chem_comp_id
pdbx_reference_molecule.formula_weight
pdbx_reference_molecule.release_status
pdbx_reference_molecule.replaces
pdbx_reference_molecule.replaced_by
pdbx_reference_molecule.compound_details
pdbx_reference_molecule.description
pdbx_reference_molecule.representative_PDB_id_code
pdbx_reference_entity_list.prd_id
pdbx_reference_entity_list.ref_entity_id
pdbx_reference_entity_list.component_id
pdbx_reference_entity_list.type
pdbx_reference_entity_list.details
pdbx_reference_entity_nonpoly.prd_id
pdbx_reference_entity_nonpoly.ref_entity_id
pdbx_reference_entity_nonpoly.name
pdbx_reference_entity_nonpoly.chem_comp_id
pdbx_reference_entity_link.prd_id
pdbx_reference_entity_link.link_id
pdbx_reference_entity_link.link_class
pdbx_reference_entity_link.ref_entity_id_1
pdbx_reference_entity_link.entity_seq_num_1
pdbx_reference_entity_link.comp_id_1
pdbx_reference_entity_link.atom_id_1
pdbx_reference_entity_link.ref_entity_id_2
pdbx_reference_entity_link.entity_seq_num_2
pdbx_reference_entity_link.comp_id_2
pdbx_reference_entity_link.atom_id_2
pdbx_reference_entity_link.value_order
pdbx_reference_entity_link.component_1
pdbx_reference_entity_link.component_2
pdbx_reference_entity_link.details
pdbx_reference_entity_poly_link.prd_id
pdbx_reference_entity_poly_link.ref_entity_id
pdbx_reference_entity_poly_link.link_id
pdbx_reference_entity_poly_link.atom_id_1
pdbx_reference_entity_poly_link.comp_id_1
pdbx_reference_entity_poly_link.entity_seq_num_1
pdbx_reference_entity_poly_link.atom_id_2
pdbx_reference_entity_poly_link.comp_id_2
pdbx_reference_entity_poly_link.entity_seq_num_2
pdbx_reference_entity_poly_link.value_order
pdbx_reference_entity_poly_link.component_id
pdbx_reference_entity_poly.prd_id
pdbx_reference_entity_poly.ref_entity_id
pdbx_reference_entity_poly.db_code
pdbx_reference_entity_poly.db_name
pdbx_reference_entity_poly.type
pdbx_reference_entity_sequence.prd_id
pdbx_reference_entity_sequence.ref_entity_id
pdbx_reference_entity_sequence.type
pdbx_reference_entity_sequence.NRP_flag
pdbx_reference_entity_sequence.one_letter_codes
pdbx_reference_entity_poly_seq.prd_id
pdbx_reference_entity_poly_seq.ref_entity_id
pdbx_reference_entity_poly_seq.num
pdbx_reference_entity_poly_seq.mon_id
pdbx_reference_entity_poly_seq.parent_mon_id
pdbx_reference_entity_poly_seq.hetero
pdbx_reference_entity_poly_seq.observed
pdbx_reference_entity_src_nat.prd_id
pdbx_reference_entity_src_nat.ref_entity_id
pdbx_reference_entity_src_nat.ordinal
pdbx_reference_entity_src_nat.taxid
pdbx_reference_entity_src_nat.organism_scientific
pdbx_reference_entity_src_nat.db_code
pdbx_reference_entity_src_nat.db_name
pdbx_prd_audit.prd_id
pdbx_prd_audit.date
pdbx_prd_audit.processing_site
pdbx_prd_audit.action_type
1 pdbx_reference_molecule.prd_id
2 pdbx_reference_molecule.name
3 pdbx_reference_molecule.represent_as
4 pdbx_reference_molecule.type
5 pdbx_reference_molecule.type_evidence_code
6 pdbx_reference_molecule.class
7 pdbx_reference_molecule.class_evidence_code
8 pdbx_reference_molecule.formula
9 pdbx_reference_molecule.chem_comp_id
10 pdbx_reference_molecule.formula_weight
11 pdbx_reference_molecule.release_status
12 pdbx_reference_molecule.replaces
13 pdbx_reference_molecule.replaced_by
14 pdbx_reference_molecule.compound_details
15 pdbx_reference_molecule.description
16 pdbx_reference_molecule.representative_PDB_id_code
17 pdbx_reference_entity_list.prd_id
18 pdbx_reference_entity_list.ref_entity_id
19 pdbx_reference_entity_list.component_id
20 pdbx_reference_entity_list.type
21 pdbx_reference_entity_list.details
22 pdbx_reference_entity_nonpoly.prd_id
23 pdbx_reference_entity_nonpoly.ref_entity_id
24 pdbx_reference_entity_nonpoly.name
25 pdbx_reference_entity_nonpoly.chem_comp_id
26 pdbx_reference_entity_link.prd_id
27 pdbx_reference_entity_link.link_id
28 pdbx_reference_entity_link.link_class
29 pdbx_reference_entity_link.ref_entity_id_1
30 pdbx_reference_entity_link.entity_seq_num_1
31 pdbx_reference_entity_link.comp_id_1
32 pdbx_reference_entity_link.atom_id_1
33 pdbx_reference_entity_link.ref_entity_id_2
34 pdbx_reference_entity_link.entity_seq_num_2
35 pdbx_reference_entity_link.comp_id_2
36 pdbx_reference_entity_link.atom_id_2
37 pdbx_reference_entity_link.value_order
38 pdbx_reference_entity_link.component_1
39 pdbx_reference_entity_link.component_2
40 pdbx_reference_entity_link.details
41 pdbx_reference_entity_poly_link.prd_id
42 pdbx_reference_entity_poly_link.ref_entity_id
43 pdbx_reference_entity_poly_link.link_id
44 pdbx_reference_entity_poly_link.atom_id_1
45 pdbx_reference_entity_poly_link.comp_id_1
46 pdbx_reference_entity_poly_link.entity_seq_num_1
47 pdbx_reference_entity_poly_link.atom_id_2
48 pdbx_reference_entity_poly_link.comp_id_2
49 pdbx_reference_entity_poly_link.entity_seq_num_2
50 pdbx_reference_entity_poly_link.value_order
51 pdbx_reference_entity_poly_link.component_id
52 pdbx_reference_entity_poly.prd_id
53 pdbx_reference_entity_poly.ref_entity_id
54 pdbx_reference_entity_poly.db_code
55 pdbx_reference_entity_poly.db_name
56 pdbx_reference_entity_poly.type
57 pdbx_reference_entity_sequence.prd_id
58 pdbx_reference_entity_sequence.ref_entity_id
59 pdbx_reference_entity_sequence.type
60 pdbx_reference_entity_sequence.NRP_flag
61 pdbx_reference_entity_sequence.one_letter_codes
62 pdbx_reference_entity_poly_seq.prd_id
63 pdbx_reference_entity_poly_seq.ref_entity_id
64 pdbx_reference_entity_poly_seq.num
65 pdbx_reference_entity_poly_seq.mon_id
66 pdbx_reference_entity_poly_seq.parent_mon_id
67 pdbx_reference_entity_poly_seq.hetero
68 pdbx_reference_entity_poly_seq.observed
69 pdbx_reference_entity_src_nat.prd_id
70 pdbx_reference_entity_src_nat.ref_entity_id
71 pdbx_reference_entity_src_nat.ordinal
72 pdbx_reference_entity_src_nat.taxid
73 pdbx_reference_entity_src_nat.organism_scientific
74 pdbx_reference_entity_src_nat.db_code
75 pdbx_reference_entity_src_nat.db_name
76 pdbx_prd_audit.prd_id
77 pdbx_prd_audit.date
78 pdbx_prd_audit.processing_site
79 pdbx_prd_audit.action_type

View File

@@ -1,60 +0,0 @@
chem_comp.id
chem_comp.name
chem_comp.type
chem_comp.pdbx_type
chem_comp.formula
chem_comp.mon_nstd_parent_comp_id
chem_comp.pdbx_synonyms
chem_comp.pdbx_formal_charge
chem_comp.pdbx_initial_date
chem_comp.pdbx_modified_date
chem_comp.pdbx_ambiguous_flag
chem_comp.pdbx_release_status
chem_comp.pdbx_replaced_by
chem_comp.pdbx_replaces
chem_comp.formula_weight
chem_comp.one_letter_code
chem_comp.three_letter_code
chem_comp.pdbx_model_coordinates_details
chem_comp.pdbx_model_coordinates_missing_flag
chem_comp.pdbx_ideal_coordinates_details
chem_comp.pdbx_ideal_coordinates_missing_flag
chem_comp.pdbx_model_coordinates_db_code
chem_comp.pdbx_processing_site
chem_comp_atom.comp_id
chem_comp_atom.atom_id
chem_comp_atom.alt_atom_id
chem_comp_atom.type_symbol
chem_comp_atom.charge
chem_comp_atom.pdbx_align
chem_comp_atom.pdbx_aromatic_flag
chem_comp_atom.pdbx_leaving_atom_flag
chem_comp_atom.pdbx_stereo_config
chem_comp_atom.model_Cartn_x
chem_comp_atom.model_Cartn_y
chem_comp_atom.model_Cartn_z
chem_comp_atom.pdbx_model_Cartn_x_ideal
chem_comp_atom.pdbx_model_Cartn_y_ideal
chem_comp_atom.pdbx_model_Cartn_z_ideal
chem_comp_atom.pdbx_ordinal
chem_comp_bond.comp_id
chem_comp_bond.atom_id_1
chem_comp_bond.atom_id_2
chem_comp_bond.value_order
chem_comp_bond.pdbx_aromatic_flag
chem_comp_bond.pdbx_stereo_config
chem_comp_bond.pdbx_ordinal
pdbx_chem_comp_descriptor.comp_id
pdbx_chem_comp_descriptor.type
pdbx_chem_comp_descriptor.program
pdbx_chem_comp_descriptor.program_version
pdbx_chem_comp_descriptor.descriptor
pdbx_chem_comp_identifier.comp_id
pdbx_chem_comp_identifier.type
pdbx_chem_comp_identifier.program
pdbx_chem_comp_identifier.program_version
pdbx_chem_comp_identifier.identifier
1 chem_comp.id
2 chem_comp.name
3 chem_comp.type
4 chem_comp.pdbx_type
5 chem_comp.formula
6 chem_comp.mon_nstd_parent_comp_id
7 chem_comp.pdbx_synonyms
8 chem_comp.pdbx_formal_charge
9 chem_comp.pdbx_initial_date
10 chem_comp.pdbx_modified_date
11 chem_comp.pdbx_ambiguous_flag
12 chem_comp.pdbx_release_status
13 chem_comp.pdbx_replaced_by
14 chem_comp.pdbx_replaces
15 chem_comp.formula_weight
16 chem_comp.one_letter_code
17 chem_comp.three_letter_code
18 chem_comp.pdbx_model_coordinates_details
19 chem_comp.pdbx_model_coordinates_missing_flag
20 chem_comp.pdbx_ideal_coordinates_details
21 chem_comp.pdbx_ideal_coordinates_missing_flag
22 chem_comp.pdbx_model_coordinates_db_code
23 chem_comp.pdbx_processing_site
24 chem_comp_atom.comp_id
25 chem_comp_atom.atom_id
26 chem_comp_atom.alt_atom_id
27 chem_comp_atom.type_symbol
28 chem_comp_atom.charge
29 chem_comp_atom.pdbx_align
30 chem_comp_atom.pdbx_aromatic_flag
31 chem_comp_atom.pdbx_leaving_atom_flag
32 chem_comp_atom.pdbx_stereo_config
33 chem_comp_atom.model_Cartn_x
34 chem_comp_atom.model_Cartn_y
35 chem_comp_atom.model_Cartn_z
36 chem_comp_atom.pdbx_model_Cartn_x_ideal
37 chem_comp_atom.pdbx_model_Cartn_y_ideal
38 chem_comp_atom.pdbx_model_Cartn_z_ideal
39 chem_comp_atom.pdbx_ordinal
40 chem_comp_bond.comp_id
41 chem_comp_bond.atom_id_1
42 chem_comp_bond.atom_id_2
43 chem_comp_bond.value_order
44 chem_comp_bond.pdbx_aromatic_flag
45 chem_comp_bond.pdbx_stereo_config
46 chem_comp_bond.pdbx_ordinal
47 pdbx_chem_comp_descriptor.comp_id
48 pdbx_chem_comp_descriptor.type
49 pdbx_chem_comp_descriptor.program
50 pdbx_chem_comp_descriptor.program_version
51 pdbx_chem_comp_descriptor.descriptor
52 pdbx_chem_comp_identifier.comp_id
53 pdbx_chem_comp_identifier.type
54 pdbx_chem_comp_identifier.program
55 pdbx_chem_comp_identifier.program_version
56 pdbx_chem_comp_identifier.identifier

View File

@@ -1,805 +0,0 @@
atom_sites.entry_id
atom_sites.fract_transf_matrix
atom_sites.fract_transf_vector
atom_site.group_PDB
atom_site.id
atom_site.type_symbol
atom_site.label_atom_id
atom_site.label_alt_id
atom_site.label_comp_id
atom_site.label_asym_id
atom_site.label_entity_id
atom_site.label_seq_id
atom_site.pdbx_PDB_ins_code
atom_site.pdbx_formal_charge
atom_site.Cartn_x
atom_site.Cartn_y
atom_site.Cartn_z
atom_site.occupancy
atom_site.B_iso_or_equiv
atom_site.auth_atom_id
atom_site.auth_comp_id
atom_site.auth_asym_id
atom_site.auth_seq_id
atom_site.pdbx_PDB_model_num
atom_site.ihm_model_id
atom_site_anisotrop.id
atom_site_anisotrop.U
atom_site_anisotrop.U_esd
atom_site_anisotrop.pdbx_PDB_ins_code
atom_site_anisotrop.pdbx_auth_asym_id
atom_site_anisotrop.pdbx_auth_atom_id
atom_site_anisotrop.pdbx_auth_comp_id
atom_site_anisotrop.pdbx_auth_seq_id
atom_site_anisotrop.pdbx_label_alt_id
atom_site_anisotrop.pdbx_label_asym_id
atom_site_anisotrop.pdbx_label_atom_id
atom_site_anisotrop.pdbx_label_comp_id
atom_site_anisotrop.pdbx_label_seq_id
atom_site_anisotrop.type_symbol
chem_comp.id
chem_comp.type
chem_comp.mon_nstd_flag
chem_comp.name
chem_comp.pdbx_synonyms
chem_comp.formula
chem_comp.formula_weight
chem_comp_bond.comp_id
chem_comp_bond.pdbx_stereo_config
chem_comp_bond.pdbx_ordinal
chem_comp_bond.pdbx_aromatic_flag
chem_comp_bond.atom_id_1
chem_comp_bond.atom_id_2
chem_comp_bond.value_order
pdbx_chem_comp_identifier.comp_id
pdbx_chem_comp_identifier.type
pdbx_chem_comp_identifier.program
pdbx_chem_comp_identifier.program_version
pdbx_chem_comp_identifier.identifier
pdbx_chem_comp_related.comp_id
pdbx_chem_comp_related.related_comp_id
pdbx_chem_comp_related.relationship_type
pdbx_chem_comp_related.details
pdbx_chem_comp_synonyms.comp_id
pdbx_chem_comp_synonyms.name
pdbx_chem_comp_synonyms.provenance
cell.entry_id
cell.length_a
cell.length_b
cell.length_c
cell.angle_alpha
cell.angle_beta
cell.angle_gamma
cell.Z_PDB
cell.pdbx_unique_axis
pdbx_database_related.db_name
pdbx_database_related.details
pdbx_database_related.db_id
pdbx_database_related.content_type
pdbx_database_status.status_code
pdbx_database_status.status_code_sf
pdbx_database_status.status_code_mr
pdbx_database_status.entry_id
pdbx_database_status.recvd_initial_deposition_date
pdbx_database_status.SG_entry
pdbx_database_status.deposit_site
pdbx_database_status.process_site
pdbx_database_status.status_code_cs
pdbx_database_status.methods_development_category
pdbx_database_status.pdb_format_compatible
entity.id
entity.type
entity.src_method
entity.pdbx_description
entity.formula_weight
entity.pdbx_number_of_molecules
entity.details
entity.pdbx_mutation
entity.pdbx_fragment
entity.pdbx_ec
entity_poly.entity_id
entity_poly.type
entity_poly.nstd_linkage
entity_poly.nstd_monomer
entity_poly.pdbx_seq_one_letter_code
entity_poly.pdbx_seq_one_letter_code_can
entity_poly.pdbx_strand_id
entity_poly.pdbx_target_identifier
entity_poly_seq.entity_id
entity_poly_seq.num
entity_poly_seq.mon_id
entity_poly_seq.hetero
entity_src_gen.entity_id
entity_src_gen.pdbx_src_id
entity_src_gen.pdbx_beg_seq_num
entity_src_gen.pdbx_end_seq_num
entity_src_gen.pdbx_gene_src_gene
entity_src_gen.pdbx_gene_src_scientific_name
entity_src_gen.plasmid_name
entity_src_nat.entity_id
entity_src_nat.pdbx_src_id
entity_src_nat.pdbx_beg_seq_num
entity_src_nat.pdbx_end_seq_num
entity_src_nat.pdbx_organism_scientific
entity_src_nat.pdbx_plasmid_name
pdbx_entity_instance_feature.ordinal
pdbx_entity_instance_feature.feature_type
pdbx_entity_instance_feature.details
pdbx_entity_instance_feature.asym_id
pdbx_entity_instance_feature.comp_id
pdbx_entity_instance_feature.seq_num
pdbx_entity_instance_feature.auth_asym_id
pdbx_entity_instance_feature.auth_comp_id
pdbx_entity_instance_feature.auth_seq_num
pdbx_entity_src_syn.entity_id
pdbx_entity_src_syn.pdbx_src_id
pdbx_entity_src_syn.pdbx_beg_seq_num
pdbx_entity_src_syn.pdbx_end_seq_num
pdbx_entity_src_syn.organism_scientific
pdbx_entity_branch.entity_id
pdbx_entity_branch.type
pdbx_entity_branch_list.entity_id
pdbx_entity_branch_list.comp_id
pdbx_entity_branch_list.num
pdbx_entity_branch_list.hetero
pdbx_entity_branch_link.link_id
pdbx_entity_branch_link.entity_id
pdbx_entity_branch_link.entity_branch_list_num_1
pdbx_entity_branch_link.comp_id_1
pdbx_entity_branch_link.atom_id_1
pdbx_entity_branch_link.leaving_atom_id_1
pdbx_entity_branch_link.atom_stereo_config_1
pdbx_entity_branch_link.entity_branch_list_num_2
pdbx_entity_branch_link.comp_id_2
pdbx_entity_branch_link.atom_id_2
pdbx_entity_branch_link.leaving_atom_id_2
pdbx_entity_branch_link.atom_stereo_config_2
pdbx_entity_branch_link.value_order
pdbx_entity_branch_link.details
pdbx_branch_scheme.asym_id
pdbx_branch_scheme.entity_id
pdbx_branch_scheme.mon_id
pdbx_branch_scheme.num
pdbx_branch_scheme.auth_asym_id
pdbx_branch_scheme.auth_mon_id
pdbx_branch_scheme.auth_seq_num
pdbx_branch_scheme.hetero
pdbx_branch_scheme.pdb_mon_id
pdbx_branch_scheme.pdb_asym_id
pdbx_branch_scheme.pdb_seq_num
pdbx_entity_branch_descriptor.ordinal
pdbx_entity_branch_descriptor.entity_id
pdbx_entity_branch_descriptor.descriptor
pdbx_entity_branch_descriptor.type
pdbx_entity_branch_descriptor.program
pdbx_entity_branch_descriptor.program_version
pdbx_entity_nonpoly.entity_id
pdbx_entity_nonpoly.name
pdbx_entity_nonpoly.comp_id
pdbx_nonpoly_scheme.asym_id
pdbx_nonpoly_scheme.entity_id
pdbx_nonpoly_scheme.mon_id
pdbx_nonpoly_scheme.ndb_seq_num
pdbx_nonpoly_scheme.pdb_seq_num
pdbx_nonpoly_scheme.auth_seq_num
pdbx_nonpoly_scheme.pdb_mon_id
pdbx_nonpoly_scheme.auth_mon_id
pdbx_nonpoly_scheme.pdb_strand_id
pdbx_nonpoly_scheme.pdb_ins_code
entry.id
audit_conform.dict_name
audit_conform.dict_version
audit_conform.dict_location
database_2.database_id
database_2.database_code
audit_author.name
audit_author.pdbx_ordinal
audit_author.identifier_ORCID
citation.id
citation.title
citation.journal_abbrev
citation.journal_volume
citation.page_first
citation.page_last
citation.year
citation.journal_id_ASTM
citation.country
citation.journal_id_ISSN
citation.journal_id_CSD
citation.book_publisher
citation.pdbx_database_id_PubMed
citation.pdbx_database_id_DOI
citation_author.citation_id
citation_author.name
citation_author.ordinal
exptl.entry_id
exptl.method
struct.entry_id
struct.title
struct.pdbx_descriptor
struct_asym.id
struct_asym.pdbx_blank_PDB_chainid_flag
struct_asym.pdbx_modified
struct_asym.entity_id
struct_asym.details
struct_conf.conf_type_id
struct_conf.id
struct_conf.pdbx_PDB_helix_id
struct_conf.beg_label_comp_id
struct_conf.beg_label_asym_id
struct_conf.beg_label_seq_id
struct_conf.pdbx_beg_PDB_ins_code
struct_conf.end_label_comp_id
struct_conf.end_label_asym_id
struct_conf.end_label_seq_id
struct_conf.pdbx_end_PDB_ins_code
struct_conf.beg_auth_comp_id
struct_conf.beg_auth_asym_id
struct_conf.beg_auth_seq_id
struct_conf.end_auth_comp_id
struct_conf.end_auth_asym_id
struct_conf.end_auth_seq_id
struct_conf.pdbx_PDB_helix_class
struct_conf.details
struct_conf.pdbx_PDB_helix_length
struct_conn.id
struct_conn.conn_type_id
struct_conn.pdbx_PDB_id
struct_conn.ptnr1_label_asym_id
struct_conn.ptnr1_label_comp_id
struct_conn.ptnr1_label_seq_id
struct_conn.ptnr1_label_atom_id
struct_conn.pdbx_ptnr1_label_alt_id
struct_conn.pdbx_ptnr1_PDB_ins_code
struct_conn.pdbx_ptnr1_standard_comp_id
struct_conn.ptnr1_symmetry
struct_conn.ptnr2_label_asym_id
struct_conn.ptnr2_label_comp_id
struct_conn.ptnr2_label_seq_id
struct_conn.ptnr2_label_atom_id
struct_conn.pdbx_ptnr2_label_alt_id
struct_conn.pdbx_ptnr2_PDB_ins_code
struct_conn.ptnr1_auth_asym_id
struct_conn.ptnr1_auth_comp_id
struct_conn.ptnr1_auth_seq_id
struct_conn.ptnr2_auth_asym_id
struct_conn.ptnr2_auth_comp_id
struct_conn.ptnr2_auth_seq_id
struct_conn.ptnr2_symmetry
struct_conn.pdbx_ptnr3_label_atom_id
struct_conn.pdbx_ptnr3_label_seq_id
struct_conn.pdbx_ptnr3_label_comp_id
struct_conn.pdbx_ptnr3_label_asym_id
struct_conn.pdbx_ptnr3_label_alt_id
struct_conn.pdbx_ptnr3_PDB_ins_code
struct_conn.details
struct_conn.pdbx_dist_value
struct_conn.pdbx_value_order
struct_conn_type.id
struct_conn_type.criteria
struct_conn_type.reference
struct_keywords.entry_id
struct_keywords.pdbx_keywords
struct_keywords.text
struct_ncs_oper.id
struct_ncs_oper.code
struct_ncs_oper.matrix
struct_ncs_oper.vector
struct_ncs_oper.details
struct_sheet_range.sheet_id
struct_sheet_range.id
struct_sheet_range.beg_label_comp_id
struct_sheet_range.beg_label_asym_id
struct_sheet_range.beg_label_seq_id
struct_sheet_range.pdbx_beg_PDB_ins_code
struct_sheet_range.end_label_comp_id
struct_sheet_range.end_label_asym_id
struct_sheet_range.end_label_seq_id
struct_sheet_range.pdbx_end_PDB_ins_code
struct_sheet_range.beg_auth_comp_id
struct_sheet_range.beg_auth_asym_id
struct_sheet_range.beg_auth_seq_id
struct_sheet_range.end_auth_comp_id
struct_sheet_range.end_auth_asym_id
struct_sheet_range.end_auth_seq_id
struct_site.id
struct_site.pdbx_evidence_code
struct_site.pdbx_auth_asym_id
struct_site.pdbx_auth_comp_id
struct_site.pdbx_auth_seq_id
struct_site.pdbx_auth_ins_code
struct_site.pdbx_num_residues
struct_site.details
struct_site_gen.id
struct_site_gen.site_id
struct_site_gen.pdbx_num_res
struct_site_gen.label_comp_id
struct_site_gen.label_asym_id
struct_site_gen.label_seq_id
struct_site_gen.pdbx_auth_ins_code
struct_site_gen.auth_comp_id
struct_site_gen.auth_asym_id
struct_site_gen.auth_seq_id
struct_site_gen.label_atom_id
struct_site_gen.label_alt_id
struct_site_gen.symmetry
struct_site_gen.details
symmetry.entry_id
symmetry.cell_setting
symmetry.Int_Tables_number
symmetry.space_group_name_Hall
symmetry.space_group_name_H-M
pdbx_molecule.instance_id
pdbx_molecule.prd_id
pdbx_molecule.asym_id
pdbx_molecule_features.prd_id
pdbx_molecule_features.name
pdbx_molecule_features.type
pdbx_molecule_features.class
pdbx_molecule_features.details
pdbx_reference_entity_link.prd_id
pdbx_reference_entity_link.link_id
pdbx_reference_entity_link.link_class
pdbx_reference_entity_link.ref_entity_id_1
pdbx_reference_entity_link.entity_seq_num_1
pdbx_reference_entity_link.comp_id_1
pdbx_reference_entity_link.atom_id_1
pdbx_reference_entity_link.ref_entity_id_2
pdbx_reference_entity_link.entity_seq_num_2
pdbx_reference_entity_link.comp_id_2
pdbx_reference_entity_link.atom_id_2
pdbx_reference_entity_link.value_order
pdbx_reference_entity_link.component_1
pdbx_reference_entity_link.component_2
pdbx_reference_entity_link.details
pdbx_reference_entity_list.prd_id
pdbx_reference_entity_list.ref_entity_id
pdbx_reference_entity_list.component_id
pdbx_reference_entity_list.type
pdbx_reference_entity_list.details
pdbx_reference_entity_poly_link.prd_id
pdbx_reference_entity_poly_link.ref_entity_id
pdbx_reference_entity_poly_link.link_id
pdbx_reference_entity_poly_link.atom_id_1
pdbx_reference_entity_poly_link.comp_id_1
pdbx_reference_entity_poly_link.entity_seq_num_1
pdbx_reference_entity_poly_link.atom_id_2
pdbx_reference_entity_poly_link.comp_id_2
pdbx_reference_entity_poly_link.entity_seq_num_2
pdbx_reference_entity_poly_link.value_order
pdbx_reference_entity_poly_link.component_id
pdbx_struct_assembly.id
pdbx_struct_assembly.details
pdbx_struct_assembly.method_details
pdbx_struct_assembly.oligomeric_details
pdbx_struct_assembly.oligomeric_count
pdbx_struct_assembly_gen.assembly_id
pdbx_struct_assembly_gen.oper_expression
pdbx_struct_assembly_gen.asym_id_list
pdbx_struct_oper_list.id
pdbx_struct_oper_list.type
pdbx_struct_oper_list.name
pdbx_struct_oper_list.symmetry_operation
pdbx_struct_oper_list.matrix
pdbx_struct_oper_list.vector
pdbx_struct_mod_residue.id
pdbx_struct_mod_residue.label_asym_id
pdbx_struct_mod_residue.label_seq_id
pdbx_struct_mod_residue.label_comp_id
pdbx_struct_mod_residue.auth_asym_id
pdbx_struct_mod_residue.auth_seq_id
pdbx_struct_mod_residue.auth_comp_id
pdbx_struct_mod_residue.PDB_ins_code
pdbx_struct_mod_residue.parent_comp_id
pdbx_struct_mod_residue.details
pdbx_unobs_or_zero_occ_residues.id
pdbx_unobs_or_zero_occ_residues.PDB_model_num
pdbx_unobs_or_zero_occ_residues.polymer_flag
pdbx_unobs_or_zero_occ_residues.occupancy_flag
pdbx_unobs_or_zero_occ_residues.auth_asym_id
pdbx_unobs_or_zero_occ_residues.auth_comp_id
pdbx_unobs_or_zero_occ_residues.auth_seq_id
pdbx_unobs_or_zero_occ_residues.PDB_ins_code
pdbx_unobs_or_zero_occ_residues.label_asym_id
pdbx_unobs_or_zero_occ_residues.label_comp_id
pdbx_unobs_or_zero_occ_residues.label_seq_id
ihm_struct_assembly.id
ihm_struct_assembly.name
ihm_struct_assembly.description
ihm_struct_assembly_details.id
ihm_struct_assembly_details.assembly_id
ihm_struct_assembly_details.parent_assembly_id
ihm_struct_assembly_details.entity_description
ihm_struct_assembly_details.entity_id
ihm_struct_assembly_details.asym_id
ihm_struct_assembly_details.entity_poly_segment_id
ihm_model_representation.id
ihm_model_representation.name
ihm_model_representation.details
ihm_model_representation_details.id
ihm_model_representation_details.representation_id
ihm_model_representation_details.entity_id
ihm_model_representation_details.entity_description
ihm_model_representation_details.entity_asym_id
ihm_model_representation_details.entity_poly_segment_id
ihm_model_representation_details.model_object_primitive
ihm_model_representation_details.starting_model_id
ihm_model_representation_details.model_mode
ihm_model_representation_details.model_granularity
ihm_model_representation_details.model_object_count
ihm_external_reference_info.reference_id
ihm_external_reference_info.reference_provider
ihm_external_reference_info.reference_type
ihm_external_reference_info.reference
ihm_external_reference_info.refers_to
ihm_external_reference_info.associated_url
ihm_external_files.id
ihm_external_files.reference_id
ihm_external_files.file_path
ihm_external_files.content_type
ihm_external_files.file_size_bytes
ihm_external_files.details
ihm_dataset_list.id
ihm_dataset_list.data_type
ihm_dataset_list.database_hosted
ihm_dataset_group.id
ihm_dataset_group.name
ihm_dataset_group.application
ihm_dataset_group.details
ihm_dataset_group_link.group_id
ihm_dataset_group_link.dataset_list_id
ihm_dataset_external_reference.id
ihm_dataset_external_reference.dataset_list_id
ihm_dataset_external_reference.file_id
ihm_dataset_related_db_reference.id
ihm_dataset_related_db_reference.dataset_list_id
ihm_dataset_related_db_reference.db_name
ihm_dataset_related_db_reference.accession_code
ihm_dataset_related_db_reference.version
ihm_dataset_related_db_reference.details
ihm_related_datasets.dataset_list_id_derived
ihm_related_datasets.dataset_list_id_primary
ihm_poly_residue_feature.ordinal_id
ihm_poly_residue_feature.feature_id
ihm_poly_residue_feature.entity_id
ihm_poly_residue_feature.asym_id
ihm_poly_residue_feature.seq_id_begin
ihm_poly_residue_feature.comp_id_begin
ihm_poly_residue_feature.seq_id_end
ihm_poly_residue_feature.comp_id_end
ihm_feature_list.feature_id
ihm_feature_list.feature_type
ihm_feature_list.entity_type
ihm_cross_link_list.id
ihm_cross_link_list.group_id
ihm_cross_link_list.entity_description_1
ihm_cross_link_list.entity_id_1
ihm_cross_link_list.seq_id_1
ihm_cross_link_list.comp_id_1
ihm_cross_link_list.entity_description_2
ihm_cross_link_list.entity_id_2
ihm_cross_link_list.seq_id_2
ihm_cross_link_list.comp_id_2
ihm_cross_link_list.linker_type
ihm_cross_link_list.dataset_list_id
ihm_cross_link_restraint.id
ihm_cross_link_restraint.group_id
ihm_cross_link_restraint.entity_id_1
ihm_cross_link_restraint.asym_id_1
ihm_cross_link_restraint.seq_id_1
ihm_cross_link_restraint.atom_id_1
ihm_cross_link_restraint.comp_id_1
ihm_cross_link_restraint.entity_id_2
ihm_cross_link_restraint.asym_id_2
ihm_cross_link_restraint.seq_id_2
ihm_cross_link_restraint.atom_id_2
ihm_cross_link_restraint.comp_id_2
ihm_cross_link_restraint.restraint_type
ihm_cross_link_restraint.conditional_crosslink_flag
ihm_cross_link_restraint.model_granularity
ihm_cross_link_restraint.distance_threshold
ihm_cross_link_restraint.psi
ihm_cross_link_restraint.sigma_1
ihm_cross_link_restraint.sigma_2
ihm_cross_link_result_parameters.id
ihm_cross_link_result_parameters.restraint_id
ihm_cross_link_result_parameters.model_id
ihm_cross_link_result_parameters.psi
ihm_cross_link_result_parameters.sigma_1
ihm_cross_link_result_parameters.sigma_2
ihm_sas_restraint.id
ihm_sas_restraint.dataset_list_id
ihm_sas_restraint.model_id
ihm_sas_restraint.struct_assembly_id
ihm_sas_restraint.profile_segment_flag
ihm_sas_restraint.fitting_atom_type
ihm_sas_restraint.fitting_method
ihm_sas_restraint.fitting_state
ihm_sas_restraint.radius_of_gyration
ihm_sas_restraint.chi_value
ihm_sas_restraint.details
ihm_derived_distance_restraint.id
ihm_derived_distance_restraint.group_id
ihm_derived_distance_restraint.feature_id_1
ihm_derived_distance_restraint.feature_id_2
ihm_derived_distance_restraint.group_conditionality
ihm_derived_distance_restraint.restraint_type
ihm_derived_distance_restraint.distance_upper_limit
ihm_derived_distance_restraint.random_exclusion_fraction
ihm_derived_distance_restraint.dataset_list_id
ihm_2dem_class_average_restraint.id
ihm_2dem_class_average_restraint.dataset_list_id
ihm_2dem_class_average_restraint.number_raw_micrographs
ihm_2dem_class_average_restraint.pixel_size_width
ihm_2dem_class_average_restraint.pixel_size_height
ihm_2dem_class_average_restraint.image_resolution
ihm_2dem_class_average_restraint.image_segment_flag
ihm_2dem_class_average_restraint.number_of_projections
ihm_2dem_class_average_restraint.struct_assembly_id
ihm_2dem_class_average_restraint.details
ihm_2dem_class_average_fitting.id
ihm_2dem_class_average_fitting.restraint_id
ihm_2dem_class_average_fitting.model_id
ihm_2dem_class_average_fitting.cross_correlation_coefficient
ihm_2dem_class_average_fitting.rot_matrix
ihm_2dem_class_average_fitting.tr_vector
ihm_3dem_restraint.id
ihm_3dem_restraint.dataset_list_id
ihm_3dem_restraint.fitting_method
ihm_3dem_restraint.struct_assembly_id
ihm_3dem_restraint.number_of_gaussians
ihm_3dem_restraint.model_id
ihm_3dem_restraint.cross_correlation_coefficient
ihm_predicted_contact_restraint.id
ihm_predicted_contact_restraint.group_id
ihm_predicted_contact_restraint.entity_id_1
ihm_predicted_contact_restraint.asym_id_1
ihm_predicted_contact_restraint.seq_id_1
ihm_predicted_contact_restraint.comp_id_1
ihm_predicted_contact_restraint.rep_atom_1
ihm_predicted_contact_restraint.entity_id_2
ihm_predicted_contact_restraint.asym_id_2
ihm_predicted_contact_restraint.seq_id_2
ihm_predicted_contact_restraint.comp_id_2
ihm_predicted_contact_restraint.rep_atom_2
ihm_predicted_contact_restraint.restraint_type
ihm_predicted_contact_restraint.distance_lower_limit
ihm_predicted_contact_restraint.distance_upper_limit
ihm_predicted_contact_restraint.probability
ihm_predicted_contact_restraint.model_granularity
ihm_predicted_contact_restraint.dataset_list_id
ihm_predicted_contact_restraint.software_id
ihm_starting_model_details.starting_model_id
ihm_starting_model_details.entity_id
ihm_starting_model_details.entity_description
ihm_starting_model_details.asym_id
ihm_starting_model_details.entity_poly_segment_id
ihm_starting_model_details.starting_model_source
ihm_starting_model_details.starting_model_auth_asym_id
ihm_starting_model_details.starting_model_sequence_offset
ihm_starting_model_details.dataset_list_id
ihm_starting_comparative_models.id
ihm_starting_comparative_models.starting_model_id
ihm_starting_comparative_models.starting_model_auth_asym_id
ihm_starting_comparative_models.starting_model_seq_id_begin
ihm_starting_comparative_models.starting_model_seq_id_end
ihm_starting_comparative_models.template_auth_asym_id
ihm_starting_comparative_models.template_seq_id_begin
ihm_starting_comparative_models.template_seq_id_end
ihm_starting_comparative_models.template_sequence_identity
ihm_starting_comparative_models.template_sequence_identity_denominator
ihm_starting_comparative_models.template_dataset_list_id
ihm_starting_comparative_models.alignment_file_id
ihm_starting_model_coord.starting_model_id
ihm_starting_model_coord.group_PDB
ihm_starting_model_coord.id
ihm_starting_model_coord.type_symbol
ihm_starting_model_coord.atom_id
ihm_starting_model_coord.comp_id
ihm_starting_model_coord.entity_id
ihm_starting_model_coord.asym_id
ihm_starting_model_coord.seq_id
ihm_starting_model_coord.Cartn_x
ihm_starting_model_coord.Cartn_y
ihm_starting_model_coord.Cartn_z
ihm_starting_model_coord.B_iso_or_equiv
ihm_starting_model_coord.ordinal_id
ihm_starting_model_seq_dif.id
ihm_starting_model_seq_dif.entity_id
ihm_starting_model_seq_dif.asym_id
ihm_starting_model_seq_dif.seq_id
ihm_starting_model_seq_dif.comp_id
ihm_starting_model_seq_dif.starting_model_id
ihm_starting_model_seq_dif.db_asym_id
ihm_starting_model_seq_dif.db_seq_id
ihm_starting_model_seq_dif.db_comp_id
ihm_starting_model_seq_dif.details
ihm_modeling_protocol.id
ihm_modeling_protocol.protocol_name
ihm_modeling_protocol.num_steps
ihm_modeling_protocol_details.id
ihm_modeling_protocol_details.protocol_id
ihm_modeling_protocol_details.step_id
ihm_modeling_protocol_details.struct_assembly_id
ihm_modeling_protocol_details.dataset_group_id
ihm_modeling_protocol_details.struct_assembly_description
ihm_modeling_protocol_details.step_name
ihm_modeling_protocol_details.step_method
ihm_modeling_protocol_details.num_models_begin
ihm_modeling_protocol_details.num_models_end
ihm_modeling_protocol_details.multi_scale_flag
ihm_modeling_protocol_details.multi_state_flag
ihm_modeling_protocol_details.ordered_flag
ihm_modeling_protocol_details.software_id
ihm_modeling_protocol_details.script_file_id
ihm_modeling_post_process.id
ihm_modeling_post_process.protocol_id
ihm_modeling_post_process.analysis_id
ihm_modeling_post_process.step_id
ihm_modeling_post_process.type
ihm_modeling_post_process.feature
ihm_modeling_post_process.num_models_begin
ihm_modeling_post_process.num_models_end
ihm_ensemble_info.ensemble_id
ihm_ensemble_info.ensemble_name
ihm_ensemble_info.post_process_id
ihm_ensemble_info.model_group_id
ihm_ensemble_info.ensemble_clustering_method
ihm_ensemble_info.ensemble_clustering_feature
ihm_ensemble_info.num_ensemble_models
ihm_ensemble_info.num_ensemble_models_deposited
ihm_ensemble_info.ensemble_precision_value
ihm_ensemble_info.ensemble_file_id
ihm_localization_density_files.id
ihm_localization_density_files.file_id
ihm_localization_density_files.ensemble_id
ihm_localization_density_files.entity_id
ihm_localization_density_files.asym_id
ihm_localization_density_files.entity_poly_segment_id
ihm_model_list.model_id
ihm_model_list.model_name
ihm_model_list.assembly_id
ihm_model_list.protocol_id
ihm_model_list.representation_id
ihm_model_group.id
ihm_model_group.name
ihm_model_group.details
ihm_model_group_link.group_id
ihm_model_group_link.model_id
ihm_model_representative.id
ihm_model_representative.model_group_id
ihm_model_representative.model_id
ihm_model_representative.selection_criteria
ihm_sphere_obj_site.id
ihm_sphere_obj_site.entity_id
ihm_sphere_obj_site.seq_id_begin
ihm_sphere_obj_site.seq_id_end
ihm_sphere_obj_site.asym_id
ihm_sphere_obj_site.Cartn_x
ihm_sphere_obj_site.Cartn_y
ihm_sphere_obj_site.Cartn_z
ihm_sphere_obj_site.object_radius
ihm_sphere_obj_site.rmsf
ihm_sphere_obj_site.model_id
ihm_gaussian_obj_site.id
ihm_gaussian_obj_site.entity_id
ihm_gaussian_obj_site.seq_id_begin
ihm_gaussian_obj_site.seq_id_end
ihm_gaussian_obj_site.asym_id
ihm_gaussian_obj_site.mean_Cartn_x
ihm_gaussian_obj_site.mean_Cartn_y
ihm_gaussian_obj_site.mean_Cartn_z
ihm_gaussian_obj_site.weight
ihm_gaussian_obj_site.covariance_matrix
ihm_gaussian_obj_site.model_id
ihm_gaussian_obj_ensemble.id
ihm_gaussian_obj_ensemble.entity_id
ihm_gaussian_obj_ensemble.seq_id_begin
ihm_gaussian_obj_ensemble.seq_id_end
ihm_gaussian_obj_ensemble.asym_id
ihm_gaussian_obj_ensemble.mean_Cartn_x
ihm_gaussian_obj_ensemble.mean_Cartn_y
ihm_gaussian_obj_ensemble.mean_Cartn_z
ihm_gaussian_obj_ensemble.weight
ihm_gaussian_obj_ensemble.covariance_matrix
ihm_gaussian_obj_ensemble.ensemble_id
ihm_multi_state_modeling.state_id
ihm_multi_state_modeling.state_group_id
ihm_multi_state_modeling.population_fraction
ihm_multi_state_modeling.population_fraction_sd
ihm_multi_state_modeling.state_type
ihm_multi_state_modeling.state_name
ihm_multi_state_modeling.experiment_type
ihm_multi_state_modeling.details
1 atom_sites.entry_id
2 atom_sites.fract_transf_matrix
3 atom_sites.fract_transf_vector
4 atom_site.group_PDB
5 atom_site.id
6 atom_site.type_symbol
7 atom_site.label_atom_id
8 atom_site.label_alt_id
9 atom_site.label_comp_id
10 atom_site.label_asym_id
11 atom_site.label_entity_id
12 atom_site.label_seq_id
13 atom_site.pdbx_PDB_ins_code
14 atom_site.pdbx_formal_charge
15 atom_site.Cartn_x
16 atom_site.Cartn_y
17 atom_site.Cartn_z
18 atom_site.occupancy
19 atom_site.B_iso_or_equiv
20 atom_site.auth_atom_id
21 atom_site.auth_comp_id
22 atom_site.auth_asym_id
23 atom_site.auth_seq_id
24 atom_site.pdbx_PDB_model_num
25 atom_site.ihm_model_id
26 atom_site_anisotrop.id
27 atom_site_anisotrop.U
28 atom_site_anisotrop.U_esd
29 atom_site_anisotrop.pdbx_PDB_ins_code
30 atom_site_anisotrop.pdbx_auth_asym_id
31 atom_site_anisotrop.pdbx_auth_atom_id
32 atom_site_anisotrop.pdbx_auth_comp_id
33 atom_site_anisotrop.pdbx_auth_seq_id
34 atom_site_anisotrop.pdbx_label_alt_id
35 atom_site_anisotrop.pdbx_label_asym_id
36 atom_site_anisotrop.pdbx_label_atom_id
37 atom_site_anisotrop.pdbx_label_comp_id
38 atom_site_anisotrop.pdbx_label_seq_id
39 atom_site_anisotrop.type_symbol
40 chem_comp.id
41 chem_comp.type
42 chem_comp.mon_nstd_flag
43 chem_comp.name
44 chem_comp.pdbx_synonyms
45 chem_comp.formula
46 chem_comp.formula_weight
47 chem_comp_bond.comp_id
48 chem_comp_bond.pdbx_stereo_config
49 chem_comp_bond.pdbx_ordinal
50 chem_comp_bond.pdbx_aromatic_flag
51 chem_comp_bond.atom_id_1
52 chem_comp_bond.atom_id_2
53 chem_comp_bond.value_order
54 pdbx_chem_comp_identifier.comp_id
55 pdbx_chem_comp_identifier.type
56 pdbx_chem_comp_identifier.program
57 pdbx_chem_comp_identifier.program_version
58 pdbx_chem_comp_identifier.identifier
59 pdbx_chem_comp_related.comp_id
60 pdbx_chem_comp_related.related_comp_id
61 pdbx_chem_comp_related.relationship_type
62 pdbx_chem_comp_related.details
63 pdbx_chem_comp_synonyms.comp_id
64 pdbx_chem_comp_synonyms.name
65 pdbx_chem_comp_synonyms.provenance
66 cell.entry_id
67 cell.length_a
68 cell.length_b
69 cell.length_c
70 cell.angle_alpha
71 cell.angle_beta
72 cell.angle_gamma
73 cell.Z_PDB
74 cell.pdbx_unique_axis
75 pdbx_database_related.db_name
76 pdbx_database_related.details
77 pdbx_database_related.db_id
78 pdbx_database_related.content_type
79 pdbx_database_status.status_code
80 pdbx_database_status.status_code_sf
81 pdbx_database_status.status_code_mr
82 pdbx_database_status.entry_id
83 pdbx_database_status.recvd_initial_deposition_date
84 pdbx_database_status.SG_entry
85 pdbx_database_status.deposit_site
86 pdbx_database_status.process_site
87 pdbx_database_status.status_code_cs
88 pdbx_database_status.methods_development_category
89 pdbx_database_status.pdb_format_compatible
90 entity.id
91 entity.type
92 entity.src_method
93 entity.pdbx_description
94 entity.formula_weight
95 entity.pdbx_number_of_molecules
96 entity.details
97 entity.pdbx_mutation
98 entity.pdbx_fragment
99 entity.pdbx_ec
100 entity_poly.entity_id
101 entity_poly.type
102 entity_poly.nstd_linkage
103 entity_poly.nstd_monomer
104 entity_poly.pdbx_seq_one_letter_code
105 entity_poly.pdbx_seq_one_letter_code_can
106 entity_poly.pdbx_strand_id
107 entity_poly.pdbx_target_identifier
108 entity_poly_seq.entity_id
109 entity_poly_seq.num
110 entity_poly_seq.mon_id
111 entity_poly_seq.hetero
112 entity_src_gen.entity_id
113 entity_src_gen.pdbx_src_id
114 entity_src_gen.pdbx_beg_seq_num
115 entity_src_gen.pdbx_end_seq_num
116 entity_src_gen.pdbx_gene_src_gene
117 entity_src_gen.pdbx_gene_src_scientific_name
118 entity_src_gen.plasmid_name
119 entity_src_nat.entity_id
120 entity_src_nat.pdbx_src_id
121 entity_src_nat.pdbx_beg_seq_num
122 entity_src_nat.pdbx_end_seq_num
123 entity_src_nat.pdbx_organism_scientific
124 entity_src_nat.pdbx_plasmid_name
125 pdbx_entity_instance_feature.ordinal
126 pdbx_entity_instance_feature.feature_type
127 pdbx_entity_instance_feature.details
128 pdbx_entity_instance_feature.asym_id
129 pdbx_entity_instance_feature.comp_id
130 pdbx_entity_instance_feature.seq_num
131 pdbx_entity_instance_feature.auth_asym_id
132 pdbx_entity_instance_feature.auth_comp_id
133 pdbx_entity_instance_feature.auth_seq_num
134 pdbx_entity_src_syn.entity_id
135 pdbx_entity_src_syn.pdbx_src_id
136 pdbx_entity_src_syn.pdbx_beg_seq_num
137 pdbx_entity_src_syn.pdbx_end_seq_num
138 pdbx_entity_src_syn.organism_scientific
139 pdbx_entity_branch.entity_id
140 pdbx_entity_branch.type
141 pdbx_entity_branch_list.entity_id
142 pdbx_entity_branch_list.comp_id
143 pdbx_entity_branch_list.num
144 pdbx_entity_branch_list.hetero
145 pdbx_entity_branch_link.link_id
146 pdbx_entity_branch_link.entity_id
147 pdbx_entity_branch_link.entity_branch_list_num_1
148 pdbx_entity_branch_link.comp_id_1
149 pdbx_entity_branch_link.atom_id_1
150 pdbx_entity_branch_link.leaving_atom_id_1
151 pdbx_entity_branch_link.atom_stereo_config_1
152 pdbx_entity_branch_link.entity_branch_list_num_2
153 pdbx_entity_branch_link.comp_id_2
154 pdbx_entity_branch_link.atom_id_2
155 pdbx_entity_branch_link.leaving_atom_id_2
156 pdbx_entity_branch_link.atom_stereo_config_2
157 pdbx_entity_branch_link.value_order
158 pdbx_entity_branch_link.details
159 pdbx_branch_scheme.asym_id
160 pdbx_branch_scheme.entity_id
161 pdbx_branch_scheme.mon_id
162 pdbx_branch_scheme.num
163 pdbx_branch_scheme.auth_asym_id
164 pdbx_branch_scheme.auth_mon_id
165 pdbx_branch_scheme.auth_seq_num
166 pdbx_branch_scheme.hetero
167 pdbx_branch_scheme.pdb_mon_id
168 pdbx_branch_scheme.pdb_asym_id
169 pdbx_branch_scheme.pdb_seq_num
170 pdbx_entity_branch_descriptor.ordinal
171 pdbx_entity_branch_descriptor.entity_id
172 pdbx_entity_branch_descriptor.descriptor
173 pdbx_entity_branch_descriptor.type
174 pdbx_entity_branch_descriptor.program
175 pdbx_entity_branch_descriptor.program_version
176 pdbx_entity_nonpoly.entity_id
177 pdbx_entity_nonpoly.name
178 pdbx_entity_nonpoly.comp_id
179 pdbx_nonpoly_scheme.asym_id
180 pdbx_nonpoly_scheme.entity_id
181 pdbx_nonpoly_scheme.mon_id
182 pdbx_nonpoly_scheme.ndb_seq_num
183 pdbx_nonpoly_scheme.pdb_seq_num
184 pdbx_nonpoly_scheme.auth_seq_num
185 pdbx_nonpoly_scheme.pdb_mon_id
186 pdbx_nonpoly_scheme.auth_mon_id
187 pdbx_nonpoly_scheme.pdb_strand_id
188 pdbx_nonpoly_scheme.pdb_ins_code
189 entry.id
190 audit_conform.dict_name
191 audit_conform.dict_version
192 audit_conform.dict_location
193 database_2.database_id
194 database_2.database_code
195 audit_author.name
196 audit_author.pdbx_ordinal
197 audit_author.identifier_ORCID
198 citation.id
199 citation.title
200 citation.journal_abbrev
201 citation.journal_volume
202 citation.page_first
203 citation.page_last
204 citation.year
205 citation.journal_id_ASTM
206 citation.country
207 citation.journal_id_ISSN
208 citation.journal_id_CSD
209 citation.book_publisher
210 citation.pdbx_database_id_PubMed
211 citation.pdbx_database_id_DOI
212 citation_author.citation_id
213 citation_author.name
214 citation_author.ordinal
215 exptl.entry_id
216 exptl.method
217 struct.entry_id
218 struct.title
219 struct.pdbx_descriptor
220 struct_asym.id
221 struct_asym.pdbx_blank_PDB_chainid_flag
222 struct_asym.pdbx_modified
223 struct_asym.entity_id
224 struct_asym.details
225 struct_conf.conf_type_id
226 struct_conf.id
227 struct_conf.pdbx_PDB_helix_id
228 struct_conf.beg_label_comp_id
229 struct_conf.beg_label_asym_id
230 struct_conf.beg_label_seq_id
231 struct_conf.pdbx_beg_PDB_ins_code
232 struct_conf.end_label_comp_id
233 struct_conf.end_label_asym_id
234 struct_conf.end_label_seq_id
235 struct_conf.pdbx_end_PDB_ins_code
236 struct_conf.beg_auth_comp_id
237 struct_conf.beg_auth_asym_id
238 struct_conf.beg_auth_seq_id
239 struct_conf.end_auth_comp_id
240 struct_conf.end_auth_asym_id
241 struct_conf.end_auth_seq_id
242 struct_conf.pdbx_PDB_helix_class
243 struct_conf.details
244 struct_conf.pdbx_PDB_helix_length
245 struct_conn.id
246 struct_conn.conn_type_id
247 struct_conn.pdbx_PDB_id
248 struct_conn.ptnr1_label_asym_id
249 struct_conn.ptnr1_label_comp_id
250 struct_conn.ptnr1_label_seq_id
251 struct_conn.ptnr1_label_atom_id
252 struct_conn.pdbx_ptnr1_label_alt_id
253 struct_conn.pdbx_ptnr1_PDB_ins_code
254 struct_conn.pdbx_ptnr1_standard_comp_id
255 struct_conn.ptnr1_symmetry
256 struct_conn.ptnr2_label_asym_id
257 struct_conn.ptnr2_label_comp_id
258 struct_conn.ptnr2_label_seq_id
259 struct_conn.ptnr2_label_atom_id
260 struct_conn.pdbx_ptnr2_label_alt_id
261 struct_conn.pdbx_ptnr2_PDB_ins_code
262 struct_conn.ptnr1_auth_asym_id
263 struct_conn.ptnr1_auth_comp_id
264 struct_conn.ptnr1_auth_seq_id
265 struct_conn.ptnr2_auth_asym_id
266 struct_conn.ptnr2_auth_comp_id
267 struct_conn.ptnr2_auth_seq_id
268 struct_conn.ptnr2_symmetry
269 struct_conn.pdbx_ptnr3_label_atom_id
270 struct_conn.pdbx_ptnr3_label_seq_id
271 struct_conn.pdbx_ptnr3_label_comp_id
272 struct_conn.pdbx_ptnr3_label_asym_id
273 struct_conn.pdbx_ptnr3_label_alt_id
274 struct_conn.pdbx_ptnr3_PDB_ins_code
275 struct_conn.details
276 struct_conn.pdbx_dist_value
277 struct_conn.pdbx_value_order
278 struct_conn_type.id
279 struct_conn_type.criteria
280 struct_conn_type.reference
281 struct_keywords.entry_id
282 struct_keywords.pdbx_keywords
283 struct_keywords.text
284 struct_ncs_oper.id
285 struct_ncs_oper.code
286 struct_ncs_oper.matrix
287 struct_ncs_oper.vector
288 struct_ncs_oper.details
289 struct_sheet_range.sheet_id
290 struct_sheet_range.id
291 struct_sheet_range.beg_label_comp_id
292 struct_sheet_range.beg_label_asym_id
293 struct_sheet_range.beg_label_seq_id
294 struct_sheet_range.pdbx_beg_PDB_ins_code
295 struct_sheet_range.end_label_comp_id
296 struct_sheet_range.end_label_asym_id
297 struct_sheet_range.end_label_seq_id
298 struct_sheet_range.pdbx_end_PDB_ins_code
299 struct_sheet_range.beg_auth_comp_id
300 struct_sheet_range.beg_auth_asym_id
301 struct_sheet_range.beg_auth_seq_id
302 struct_sheet_range.end_auth_comp_id
303 struct_sheet_range.end_auth_asym_id
304 struct_sheet_range.end_auth_seq_id
305 struct_site.id
306 struct_site.pdbx_evidence_code
307 struct_site.pdbx_auth_asym_id
308 struct_site.pdbx_auth_comp_id
309 struct_site.pdbx_auth_seq_id
310 struct_site.pdbx_auth_ins_code
311 struct_site.pdbx_num_residues
312 struct_site.details
313 struct_site_gen.id
314 struct_site_gen.site_id
315 struct_site_gen.pdbx_num_res
316 struct_site_gen.label_comp_id
317 struct_site_gen.label_asym_id
318 struct_site_gen.label_seq_id
319 struct_site_gen.pdbx_auth_ins_code
320 struct_site_gen.auth_comp_id
321 struct_site_gen.auth_asym_id
322 struct_site_gen.auth_seq_id
323 struct_site_gen.label_atom_id
324 struct_site_gen.label_alt_id
325 struct_site_gen.symmetry
326 struct_site_gen.details
327 symmetry.entry_id
328 symmetry.cell_setting
329 symmetry.Int_Tables_number
330 symmetry.space_group_name_Hall
331 symmetry.space_group_name_H-M
332 pdbx_molecule.instance_id
333 pdbx_molecule.prd_id
334 pdbx_molecule.asym_id
335 pdbx_molecule_features.prd_id
336 pdbx_molecule_features.name
337 pdbx_molecule_features.type
338 pdbx_molecule_features.class
339 pdbx_molecule_features.details
340 pdbx_reference_entity_link.prd_id
341 pdbx_reference_entity_link.link_id
342 pdbx_reference_entity_link.link_class
343 pdbx_reference_entity_link.ref_entity_id_1
344 pdbx_reference_entity_link.entity_seq_num_1
345 pdbx_reference_entity_link.comp_id_1
346 pdbx_reference_entity_link.atom_id_1
347 pdbx_reference_entity_link.ref_entity_id_2
348 pdbx_reference_entity_link.entity_seq_num_2
349 pdbx_reference_entity_link.comp_id_2
350 pdbx_reference_entity_link.atom_id_2
351 pdbx_reference_entity_link.value_order
352 pdbx_reference_entity_link.component_1
353 pdbx_reference_entity_link.component_2
354 pdbx_reference_entity_link.details
355 pdbx_reference_entity_list.prd_id
356 pdbx_reference_entity_list.ref_entity_id
357 pdbx_reference_entity_list.component_id
358 pdbx_reference_entity_list.type
359 pdbx_reference_entity_list.details
360 pdbx_reference_entity_poly_link.prd_id
361 pdbx_reference_entity_poly_link.ref_entity_id
362 pdbx_reference_entity_poly_link.link_id
363 pdbx_reference_entity_poly_link.atom_id_1
364 pdbx_reference_entity_poly_link.comp_id_1
365 pdbx_reference_entity_poly_link.entity_seq_num_1
366 pdbx_reference_entity_poly_link.atom_id_2
367 pdbx_reference_entity_poly_link.comp_id_2
368 pdbx_reference_entity_poly_link.entity_seq_num_2
369 pdbx_reference_entity_poly_link.value_order
370 pdbx_reference_entity_poly_link.component_id
371 pdbx_struct_assembly.id
372 pdbx_struct_assembly.details
373 pdbx_struct_assembly.method_details
374 pdbx_struct_assembly.oligomeric_details
375 pdbx_struct_assembly.oligomeric_count
376 pdbx_struct_assembly_gen.assembly_id
377 pdbx_struct_assembly_gen.oper_expression
378 pdbx_struct_assembly_gen.asym_id_list
379 pdbx_struct_oper_list.id
380 pdbx_struct_oper_list.type
381 pdbx_struct_oper_list.name
382 pdbx_struct_oper_list.symmetry_operation
383 pdbx_struct_oper_list.matrix
384 pdbx_struct_oper_list.vector
385 pdbx_struct_mod_residue.id
386 pdbx_struct_mod_residue.label_asym_id
387 pdbx_struct_mod_residue.label_seq_id
388 pdbx_struct_mod_residue.label_comp_id
389 pdbx_struct_mod_residue.auth_asym_id
390 pdbx_struct_mod_residue.auth_seq_id
391 pdbx_struct_mod_residue.auth_comp_id
392 pdbx_struct_mod_residue.PDB_ins_code
393 pdbx_struct_mod_residue.parent_comp_id
394 pdbx_struct_mod_residue.details
395 pdbx_unobs_or_zero_occ_residues.id
396 pdbx_unobs_or_zero_occ_residues.PDB_model_num
397 pdbx_unobs_or_zero_occ_residues.polymer_flag
398 pdbx_unobs_or_zero_occ_residues.occupancy_flag
399 pdbx_unobs_or_zero_occ_residues.auth_asym_id
400 pdbx_unobs_or_zero_occ_residues.auth_comp_id
401 pdbx_unobs_or_zero_occ_residues.auth_seq_id
402 pdbx_unobs_or_zero_occ_residues.PDB_ins_code
403 pdbx_unobs_or_zero_occ_residues.label_asym_id
404 pdbx_unobs_or_zero_occ_residues.label_comp_id
405 pdbx_unobs_or_zero_occ_residues.label_seq_id
406 ihm_struct_assembly.id
407 ihm_struct_assembly.name
408 ihm_struct_assembly.description
409 ihm_struct_assembly_details.id
410 ihm_struct_assembly_details.assembly_id
411 ihm_struct_assembly_details.parent_assembly_id
412 ihm_struct_assembly_details.entity_description
413 ihm_struct_assembly_details.entity_id
414 ihm_struct_assembly_details.asym_id
415 ihm_struct_assembly_details.entity_poly_segment_id
416 ihm_model_representation.id
417 ihm_model_representation.name
418 ihm_model_representation.details
419 ihm_model_representation_details.id
420 ihm_model_representation_details.representation_id
421 ihm_model_representation_details.entity_id
422 ihm_model_representation_details.entity_description
423 ihm_model_representation_details.entity_asym_id
424 ihm_model_representation_details.entity_poly_segment_id
425 ihm_model_representation_details.model_object_primitive
426 ihm_model_representation_details.starting_model_id
427 ihm_model_representation_details.model_mode
428 ihm_model_representation_details.model_granularity
429 ihm_model_representation_details.model_object_count
430 ihm_external_reference_info.reference_id
431 ihm_external_reference_info.reference_provider
432 ihm_external_reference_info.reference_type
433 ihm_external_reference_info.reference
434 ihm_external_reference_info.refers_to
435 ihm_external_reference_info.associated_url
436 ihm_external_files.id
437 ihm_external_files.reference_id
438 ihm_external_files.file_path
439 ihm_external_files.content_type
440 ihm_external_files.file_size_bytes
441 ihm_external_files.details
442 ihm_dataset_list.id
443 ihm_dataset_list.data_type
444 ihm_dataset_list.database_hosted
445 ihm_dataset_group.id
446 ihm_dataset_group.name
447 ihm_dataset_group.application
448 ihm_dataset_group.details
449 ihm_dataset_group_link.group_id
450 ihm_dataset_group_link.dataset_list_id
451 ihm_dataset_external_reference.id
452 ihm_dataset_external_reference.dataset_list_id
453 ihm_dataset_external_reference.file_id
454 ihm_dataset_related_db_reference.id
455 ihm_dataset_related_db_reference.dataset_list_id
456 ihm_dataset_related_db_reference.db_name
457 ihm_dataset_related_db_reference.accession_code
458 ihm_dataset_related_db_reference.version
459 ihm_dataset_related_db_reference.details
460 ihm_related_datasets.dataset_list_id_derived
461 ihm_related_datasets.dataset_list_id_primary
462 ihm_poly_residue_feature.ordinal_id
463 ihm_poly_residue_feature.feature_id
464 ihm_poly_residue_feature.entity_id
465 ihm_poly_residue_feature.asym_id
466 ihm_poly_residue_feature.seq_id_begin
467 ihm_poly_residue_feature.comp_id_begin
468 ihm_poly_residue_feature.seq_id_end
469 ihm_poly_residue_feature.comp_id_end
470 ihm_feature_list.feature_id
471 ihm_feature_list.feature_type
472 ihm_feature_list.entity_type
473 ihm_cross_link_list.id
474 ihm_cross_link_list.group_id
475 ihm_cross_link_list.entity_description_1
476 ihm_cross_link_list.entity_id_1
477 ihm_cross_link_list.seq_id_1
478 ihm_cross_link_list.comp_id_1
479 ihm_cross_link_list.entity_description_2
480 ihm_cross_link_list.entity_id_2
481 ihm_cross_link_list.seq_id_2
482 ihm_cross_link_list.comp_id_2
483 ihm_cross_link_list.linker_type
484 ihm_cross_link_list.dataset_list_id
485 ihm_cross_link_restraint.id
486 ihm_cross_link_restraint.group_id
487 ihm_cross_link_restraint.entity_id_1
488 ihm_cross_link_restraint.asym_id_1
489 ihm_cross_link_restraint.seq_id_1
490 ihm_cross_link_restraint.atom_id_1
491 ihm_cross_link_restraint.comp_id_1
492 ihm_cross_link_restraint.entity_id_2
493 ihm_cross_link_restraint.asym_id_2
494 ihm_cross_link_restraint.seq_id_2
495 ihm_cross_link_restraint.atom_id_2
496 ihm_cross_link_restraint.comp_id_2
497 ihm_cross_link_restraint.restraint_type
498 ihm_cross_link_restraint.conditional_crosslink_flag
499 ihm_cross_link_restraint.model_granularity
500 ihm_cross_link_restraint.distance_threshold
501 ihm_cross_link_restraint.psi
502 ihm_cross_link_restraint.sigma_1
503 ihm_cross_link_restraint.sigma_2
504 ihm_cross_link_result_parameters.id
505 ihm_cross_link_result_parameters.restraint_id
506 ihm_cross_link_result_parameters.model_id
507 ihm_cross_link_result_parameters.psi
508 ihm_cross_link_result_parameters.sigma_1
509 ihm_cross_link_result_parameters.sigma_2
510 ihm_sas_restraint.id
511 ihm_sas_restraint.dataset_list_id
512 ihm_sas_restraint.model_id
513 ihm_sas_restraint.struct_assembly_id
514 ihm_sas_restraint.profile_segment_flag
515 ihm_sas_restraint.fitting_atom_type
516 ihm_sas_restraint.fitting_method
517 ihm_sas_restraint.fitting_state
518 ihm_sas_restraint.radius_of_gyration
519 ihm_sas_restraint.chi_value
520 ihm_sas_restraint.details
521 ihm_derived_distance_restraint.id
522 ihm_derived_distance_restraint.group_id
523 ihm_derived_distance_restraint.feature_id_1
524 ihm_derived_distance_restraint.feature_id_2
525 ihm_derived_distance_restraint.group_conditionality
526 ihm_derived_distance_restraint.restraint_type
527 ihm_derived_distance_restraint.distance_upper_limit
528 ihm_derived_distance_restraint.random_exclusion_fraction
529 ihm_derived_distance_restraint.dataset_list_id
530 ihm_2dem_class_average_restraint.id
531 ihm_2dem_class_average_restraint.dataset_list_id
532 ihm_2dem_class_average_restraint.number_raw_micrographs
533 ihm_2dem_class_average_restraint.pixel_size_width
534 ihm_2dem_class_average_restraint.pixel_size_height
535 ihm_2dem_class_average_restraint.image_resolution
536 ihm_2dem_class_average_restraint.image_segment_flag
537 ihm_2dem_class_average_restraint.number_of_projections
538 ihm_2dem_class_average_restraint.struct_assembly_id
539 ihm_2dem_class_average_restraint.details
540 ihm_2dem_class_average_fitting.id
541 ihm_2dem_class_average_fitting.restraint_id
542 ihm_2dem_class_average_fitting.model_id
543 ihm_2dem_class_average_fitting.cross_correlation_coefficient
544 ihm_2dem_class_average_fitting.rot_matrix
545 ihm_2dem_class_average_fitting.tr_vector
546 ihm_3dem_restraint.id
547 ihm_3dem_restraint.dataset_list_id
548 ihm_3dem_restraint.fitting_method
549 ihm_3dem_restraint.struct_assembly_id
550 ihm_3dem_restraint.number_of_gaussians
551 ihm_3dem_restraint.model_id
552 ihm_3dem_restraint.cross_correlation_coefficient
553 ihm_predicted_contact_restraint.id
554 ihm_predicted_contact_restraint.group_id
555 ihm_predicted_contact_restraint.entity_id_1
556 ihm_predicted_contact_restraint.asym_id_1
557 ihm_predicted_contact_restraint.seq_id_1
558 ihm_predicted_contact_restraint.comp_id_1
559 ihm_predicted_contact_restraint.rep_atom_1
560 ihm_predicted_contact_restraint.entity_id_2
561 ihm_predicted_contact_restraint.asym_id_2
562 ihm_predicted_contact_restraint.seq_id_2
563 ihm_predicted_contact_restraint.comp_id_2
564 ihm_predicted_contact_restraint.rep_atom_2
565 ihm_predicted_contact_restraint.restraint_type
566 ihm_predicted_contact_restraint.distance_lower_limit
567 ihm_predicted_contact_restraint.distance_upper_limit
568 ihm_predicted_contact_restraint.probability
569 ihm_predicted_contact_restraint.model_granularity
570 ihm_predicted_contact_restraint.dataset_list_id
571 ihm_predicted_contact_restraint.software_id
572 ihm_starting_model_details.starting_model_id
573 ihm_starting_model_details.entity_id
574 ihm_starting_model_details.entity_description
575 ihm_starting_model_details.asym_id
576 ihm_starting_model_details.entity_poly_segment_id
577 ihm_starting_model_details.starting_model_source
578 ihm_starting_model_details.starting_model_auth_asym_id
579 ihm_starting_model_details.starting_model_sequence_offset
580 ihm_starting_model_details.dataset_list_id
581 ihm_starting_comparative_models.id
582 ihm_starting_comparative_models.starting_model_id
583 ihm_starting_comparative_models.starting_model_auth_asym_id
584 ihm_starting_comparative_models.starting_model_seq_id_begin
585 ihm_starting_comparative_models.starting_model_seq_id_end
586 ihm_starting_comparative_models.template_auth_asym_id
587 ihm_starting_comparative_models.template_seq_id_begin
588 ihm_starting_comparative_models.template_seq_id_end
589 ihm_starting_comparative_models.template_sequence_identity
590 ihm_starting_comparative_models.template_sequence_identity_denominator
591 ihm_starting_comparative_models.template_dataset_list_id
592 ihm_starting_comparative_models.alignment_file_id
593 ihm_starting_model_coord.starting_model_id
594 ihm_starting_model_coord.group_PDB
595 ihm_starting_model_coord.id
596 ihm_starting_model_coord.type_symbol
597 ihm_starting_model_coord.atom_id
598 ihm_starting_model_coord.comp_id
599 ihm_starting_model_coord.entity_id
600 ihm_starting_model_coord.asym_id
601 ihm_starting_model_coord.seq_id
602 ihm_starting_model_coord.Cartn_x
603 ihm_starting_model_coord.Cartn_y
604 ihm_starting_model_coord.Cartn_z
605 ihm_starting_model_coord.B_iso_or_equiv
606 ihm_starting_model_coord.ordinal_id
607 ihm_starting_model_seq_dif.id
608 ihm_starting_model_seq_dif.entity_id
609 ihm_starting_model_seq_dif.asym_id
610 ihm_starting_model_seq_dif.seq_id
611 ihm_starting_model_seq_dif.comp_id
612 ihm_starting_model_seq_dif.starting_model_id
613 ihm_starting_model_seq_dif.db_asym_id
614 ihm_starting_model_seq_dif.db_seq_id
615 ihm_starting_model_seq_dif.db_comp_id
616 ihm_starting_model_seq_dif.details
617 ihm_modeling_protocol.id
618 ihm_modeling_protocol.protocol_name
619 ihm_modeling_protocol.num_steps
620 ihm_modeling_protocol_details.id
621 ihm_modeling_protocol_details.protocol_id
622 ihm_modeling_protocol_details.step_id
623 ihm_modeling_protocol_details.struct_assembly_id
624 ihm_modeling_protocol_details.dataset_group_id
625 ihm_modeling_protocol_details.struct_assembly_description
626 ihm_modeling_protocol_details.step_name
627 ihm_modeling_protocol_details.step_method
628 ihm_modeling_protocol_details.num_models_begin
629 ihm_modeling_protocol_details.num_models_end
630 ihm_modeling_protocol_details.multi_scale_flag
631 ihm_modeling_protocol_details.multi_state_flag
632 ihm_modeling_protocol_details.ordered_flag
633 ihm_modeling_protocol_details.software_id
634 ihm_modeling_protocol_details.script_file_id
635 ihm_modeling_post_process.id
636 ihm_modeling_post_process.protocol_id
637 ihm_modeling_post_process.analysis_id
638 ihm_modeling_post_process.step_id
639 ihm_modeling_post_process.type
640 ihm_modeling_post_process.feature
641 ihm_modeling_post_process.num_models_begin
642 ihm_modeling_post_process.num_models_end
643 ihm_ensemble_info.ensemble_id
644 ihm_ensemble_info.ensemble_name
645 ihm_ensemble_info.post_process_id
646 ihm_ensemble_info.model_group_id
647 ihm_ensemble_info.ensemble_clustering_method
648 ihm_ensemble_info.ensemble_clustering_feature
649 ihm_ensemble_info.num_ensemble_models
650 ihm_ensemble_info.num_ensemble_models_deposited
651 ihm_ensemble_info.ensemble_precision_value
652 ihm_ensemble_info.ensemble_file_id
653 ihm_localization_density_files.id
654 ihm_localization_density_files.file_id
655 ihm_localization_density_files.ensemble_id
656 ihm_localization_density_files.entity_id
657 ihm_localization_density_files.asym_id
658 ihm_localization_density_files.entity_poly_segment_id
659 ihm_model_list.model_id
660 ihm_model_list.model_name
661 ihm_model_list.assembly_id
662 ihm_model_list.protocol_id
663 ihm_model_list.representation_id
664 ihm_model_group.id
665 ihm_model_group.name
666 ihm_model_group.details
667 ihm_model_group_link.group_id
668 ihm_model_group_link.model_id
669 ihm_model_representative.id
670 ihm_model_representative.model_group_id
671 ihm_model_representative.model_id
672 ihm_model_representative.selection_criteria
673 ihm_sphere_obj_site.id
674 ihm_sphere_obj_site.entity_id
675 ihm_sphere_obj_site.seq_id_begin
676 ihm_sphere_obj_site.seq_id_end
677 ihm_sphere_obj_site.asym_id
678 ihm_sphere_obj_site.Cartn_x
679 ihm_sphere_obj_site.Cartn_y
680 ihm_sphere_obj_site.Cartn_z
681 ihm_sphere_obj_site.object_radius
682 ihm_sphere_obj_site.rmsf
683 ihm_sphere_obj_site.model_id
684 ihm_gaussian_obj_site.id
685 ihm_gaussian_obj_site.entity_id
686 ihm_gaussian_obj_site.seq_id_begin
687 ihm_gaussian_obj_site.seq_id_end
688 ihm_gaussian_obj_site.asym_id
689 ihm_gaussian_obj_site.mean_Cartn_x
690 ihm_gaussian_obj_site.mean_Cartn_y
691 ihm_gaussian_obj_site.mean_Cartn_z
692 ihm_gaussian_obj_site.weight
693 ihm_gaussian_obj_site.covariance_matrix
694 ihm_gaussian_obj_site.model_id
695 ihm_gaussian_obj_ensemble.id
696 ihm_gaussian_obj_ensemble.entity_id
697 ihm_gaussian_obj_ensemble.seq_id_begin
698 ihm_gaussian_obj_ensemble.seq_id_end
699 ihm_gaussian_obj_ensemble.asym_id
700 ihm_gaussian_obj_ensemble.mean_Cartn_x
701 ihm_gaussian_obj_ensemble.mean_Cartn_y
702 ihm_gaussian_obj_ensemble.mean_Cartn_z
703 ihm_gaussian_obj_ensemble.weight
704 ihm_gaussian_obj_ensemble.covariance_matrix
705 ihm_gaussian_obj_ensemble.ensemble_id
706 ihm_multi_state_modeling.state_id
707 ihm_multi_state_modeling.state_group_id
708 ihm_multi_state_modeling.population_fraction
709 ihm_multi_state_modeling.population_fraction_sd
710 ihm_multi_state_modeling.state_type
711 ihm_multi_state_modeling.state_name
712 ihm_multi_state_modeling.experiment_type
713 ihm_multi_state_modeling.details

View File

@@ -1,76 +0,0 @@
cell.length_a
cell.length_b
cell.length_c
cell.angle_alpha
cell.angle_beta
cell.angle_gamma
symmetry.space_group_name_H-M
entry.id
struct.title
pdbx_database_status.recvd_initial_deposition_date
pdbx_audit_revision_history.revision_date
struct_ncs_oper
pdbx_struct_assembly_gen
pdbx_struct_oper_list
entity.id
entity.type
entity.pdbx_description
entity_poly.entity_id
entity_poly.pdbx_seq_one_letter_code
entity_poly.pdbx_strand_id
exptl.method
refine.ls_d_res_low
refine.ls_R_factor_R_free
refine.ls_R_factor_R_work
atom_site.pdbx_formal_charge
atom_site.label_atom_id
atom_site.type_symbol
chem_comp.id
chem_comp.type
chem_comp.name
chem_comp_bond
atom_site.Cartn_x
atom_site.Cartn_y
atom_site.Cartn_z
atom_site.B_iso_or_equiv
atom_site.id
atom_site.label_alt_id
atom_site.occupancy
atom_site.label_seq_id
atom_site.label_comp_id
struct_sheet_range.id
struct_sheet_range.beg_label_asym_id
struct_sheet_range.beg_label_seq_id
struct_sheet_range.pdbx_beg_PDB_ins_code
struct_sheet_range.end_label_asym_id
struct_sheet_range.end_label_seq_id
struct_sheet_range.pdbx_end_PDB_ins_code
struct_conf.conf_type_id
struct_conf.id
struct_conf.beg_label_asym_id
struct_conf.beg_label_seq_id
struct_conf.pdbx_beg_PDB_ins_code
struct_conf.end_label_asym_id
struct_conf.end_label_seq_id
struct_conf.pdbx_end_PDB_ins_code
atom_site.pdbx_PDB_ins_code
atom_site.label_asym_id
atom_site.auth_asym_id
1 cell.length_a
2 cell.length_b
3 cell.length_c
4 cell.angle_alpha
5 cell.angle_beta
6 cell.angle_gamma
7 symmetry.space_group_name_H-M
8 entry.id
9 struct.title
10 pdbx_database_status.recvd_initial_deposition_date
11 pdbx_audit_revision_history.revision_date
12 struct_ncs_oper
13 pdbx_struct_assembly_gen
14 pdbx_struct_oper_list
15 entity.id
16 entity.type
17 entity.pdbx_description
18 entity_poly.entity_id
19 entity_poly.pdbx_seq_one_letter_code
20 entity_poly.pdbx_strand_id
21 exptl.method
22 refine.ls_d_res_low
23 refine.ls_R_factor_R_free
24 refine.ls_R_factor_R_work
25 atom_site.pdbx_formal_charge
26 atom_site.label_atom_id
27 atom_site.type_symbol
28 chem_comp.id
29 chem_comp.type
30 chem_comp.name
31 chem_comp_bond
32 atom_site.Cartn_x
33 atom_site.Cartn_y
34 atom_site.Cartn_z
35 atom_site.B_iso_or_equiv
36 atom_site.id
37 atom_site.label_alt_id
38 atom_site.occupancy
39 atom_site.label_seq_id
40 atom_site.label_comp_id
41 struct_sheet_range.id
42 struct_sheet_range.beg_label_asym_id
43 struct_sheet_range.beg_label_seq_id
44 struct_sheet_range.pdbx_beg_PDB_ins_code
45 struct_sheet_range.end_label_asym_id
46 struct_sheet_range.end_label_seq_id
47 struct_sheet_range.pdbx_end_PDB_ins_code
48 struct_conf.conf_type_id
49 struct_conf.id
50 struct_conf.beg_label_asym_id
51 struct_conf.beg_label_seq_id
52 struct_conf.pdbx_beg_PDB_ins_code
53 struct_conf.end_label_asym_id
54 struct_conf.end_label_seq_id
55 struct_conf.pdbx_end_PDB_ins_code
56 atom_site.pdbx_PDB_ins_code
57 atom_site.label_asym_id
58 atom_site.auth_asym_id

View File

@@ -0,0 +1,22 @@
const { generate } = require('graphql-code-generator')
const path = require('path')
const basePath = path.join(__dirname, '..', '..', 'src', 'mol-model-props', 'rcsb', 'graphql')
generate({
schema: 'http://rest-staging.rcsb.org/graphql',
documents: {
[path.join(basePath, 'symmetry.gql.ts')]: {
loader: path.join(__dirname, 'loader.js')
},
},
generates: {
[path.join(basePath, 'types.ts')]: {
plugins: ['time', 'typescript-common', 'typescript-client']
}
},
overwrite: true,
config: path.join(__dirname, 'codegen.json')
}, true).then(
() => console.log('done')
).catch(e => console.error(e))

View File

@@ -0,0 +1,6 @@
{
"flattenTypes": true,
"generatorConfig": {
"immutableTypes": true
}
}

View File

@@ -0,0 +1,14 @@
const { parse } = require('graphql');
const { readFileSync } = require('fs');
module.exports = function(docString, config) {
const str = readFileSync(docString, { encoding: 'utf-8' }).trim()
.replace(/^export default `/, '')
.replace(/`$/, '')
return [
{
filePath: docString,
content: parse(str)
}
];
};

View File

@@ -1,28 +0,0 @@
* Cyclic polymers (1sfi, 6dny, 1HVZ)
* B-DNA (1bna)
* Missing carbonyl oxygen (1gfl)
* Mono-saccharides with alt locs (1B5F)
* Microheterogeneity
* Protein (1EJG, 3NIR)
* DNA (3VOK)
* PNA: peptide nucleic acid (5eme, 1xj9)
* Peptide derived residues
* GFP chromophores (5Z6Y)
* Nucleotides that dont have a parent base set, i.e. detect purine/pyrimidine from geometry (THX in 1AUL, OMC in e.g. 5D3G)
* Bases with modified ring atoms
* DZ has C1 instead of N1 (e.g. 6I4N)
* DP has N5 instead of C5 and C7 instead of N7 (e.g. 6I4N)
* Beta & Gamma peptides (e.g. 1GAC, 6PQF)
* Mixed (heterogeneous) all-atom/trace-only RNA model (1JGQ)
* Polymers with residues with missing trace atoms (e.g. 2QFJ)
* Modified RNA bases (1y26, 5L4O)
* Discontinuous chains, i.e. gaps in the sequence (3sn6)
* Lots of sheets (1cbs)
* DNA (2np2, 1d66)
* C-alpha only (2rcj)
* Not cyclic, but termini are backbone-only and within distance but seqIds are not compatible (6SW3)
* Close backbone atoms but not linked (e.g. 4HIV)
* Non-standard residues
* Protein (1BRR, 5Z6Y)
* DNA (5D3G)
* Multiple models with different sets of ligands or missing ligands (1J6T, 1VRC, 2ICY, 1O2F)

View File

@@ -6,64 +6,133 @@ Model Server is a tool for preprocessing and querying macromolecular structure d
Installing and Running
=====================
Requires nodejs 8+.
## From GitHub
Getting the code (use node 8+):
```
git clone https://github.com/molstar/molstar
npm install
```
Afterwards, build the project source:
Customize configuration at ``src/server/model/config.ts`` to point to your data and which custom properties to include (see the [Custom Properties](#custom-properties) section). Alternatively, the config can be edited in the compiled version in ``build/node_modules/servers/model/config.js``.
Afterwards, build the project:
```
npm run build-tsc
npm run build
```
and run the server by
(or run watch mode for automatic rebuilds: ``npm run watch``)
Running the server locally for testing:
```
node lib/commonjs/servers/model/server/server
npm run model-server
```
or
```
node build/node_modules/servers/model/server
```
## From NPM
```
npm install --production molstar
./model-server
```
(or ``node node_modules\.bin\model-server`` in Windows).
The NPM package contains all the tools mentioned here as "binaries":
- ``model-server``
- ``model-server-query``
- ``model-server-preprocess``
In production it is a good idea to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
### Production use
In production it is required to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
### Memory issues
## Memory issues
Sometimes nodejs might run into problems with memory. This is usually resolved by adding the ``--max-old-space-size=8192`` parameter.
## Preprocessor
Preprocessor
============
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. ``node lib/commonjs/servers/model/preprocess`` or ``model-server-preprocess`` binary from the NPM package.
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. See the [Custom Properties](#custom-properties) section for providing custom properties.
## Usage
## Local Mode
The app works in two modes: single files and folders.
The server can be run in local/file based mode using ``node lib/commonjs/servers/model/query`` (``model-server-query`` binary from the NPM package).
Single files:
```
node build\node_modules\servers\model\preprocess -i input.cif [-oc output.cif] [-ob output.bcif] [--cfg config.json]
```
Folder:
```
node build\node_modules\servers\model\preprocess -fin input_folder [-foc output_cif_folder] [-fob output_bcif_folder] [--cfg config.json]
```
## Config
The config speficies the maximum number of processes to use (in case of folder processing) and defines sources and parameters for custom properties.
Example:
```json
{
"numProcesses": 4,
"customProperties": {
"sources": [
"./properties/pdbe"
],
"params": {
"PDBe": {
"UseFileSource": false,
"API": {
"residuewise_outlier_summary": "https://www.ebi.ac.uk/pdbe/api/validation/residuewise_outlier_summary/entry",
"preferred_assembly": "https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary",
"struct_ref_domain": "https://www.ebi.ac.uk/pdbe/api/mappings/sequence_domains"
}
}
}
}
}
```
Custom Properties
=================
This feature is still in development.
It is possible to provide property descriptors that transform data to internal representation and define how it should be exported into one or mode CIF categories. Examples of this are located in the ``mol-model-props`` module and are linked to the server in the config and ``servers/model/properties``.
It is possible to provide property descriptors that transform data to internal representation and define how it should be exported into one or mode CIF categories. Examples of this are located in the ``mol-model-props`` module and are linked to the server in the config and ``servers/model/properties``.
Local Mode
==========
The server can be run in local/file based mode:
```
node build/node_modules/servers/model/server jobs.json
```
where ``jobs.json`` is an array of
```ts
type LocalInput = {
input: string,
output: string,
query: QueryName,
modelNums?: number[],
params?: any,
binary?: boolean
}[]
```
For example
```json
[
{
"input": "c:/test/quick/1tqn.cif",
"output": "c:/test/quick/localapi/1tqn_full.cif",
"query": "full"
},
{
"input": "c:/test/quick/1tqn.cif",
"output": "c:/test/quick/localapi/1tqn_full.bcif",
"query": "full",
"params": {}
},
{
"input": "c:/test/quick/1cbs_updated.cif",
"output": "c:/test/quick/localapi/1cbs_ligint.cif",
"query": "residueInteraction",
"params": {
"atom_site": { "label_comp_id": "REA" }
}
}
]
```

View File

@@ -7,64 +7,107 @@ It uses the text based CIF and BinaryCIF formats to deliver the data to the clie
For quick info about the benefits of using the server, check out the [examples](examples.md).
Installing and Running
Installing the Server
=====================
Requires nodejs 8+.
- Install [Node.js](https://nodejs.org/en/) (tested on Node 6.* and 7.*; x64 version is strongly preferred).
- Get the code.
- Prepare the data.
- Run the server.
## From GitHub
```
git clone https://github.com/molstar/molstar
npm install
```
Afterwards, build the project source:
```
npm run build-tsc
```
and run the server by
```
node lib/commonjs/servers/volume/server
```
## From NPM
```
npm install --production molstar
./volume-server
```
(or ``node node_modules\.bin\volume-server`` in Windows).
The NPM package contains all the tools mentioned here as "binaries":
- ``volume-server``
- ``volume-server-pack``
- ``volume-server-query``
### Production use
In production it is required to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
### Memory issues
Sometimes nodejs might run into problems with memory. This is usually resolved by adding the ``--max-old-space-size=8192`` parameter.
## Preparing the Data
Preparing the Data
------------------
For the server to work, CCP4/MAP (models 0, 1, 2 are supported) input data need to be converted into a custom block format.
To achieve this, use the ``pack`` application (``node lib/commonjs/servers/volume/pack`` or ``volume-server-pack`` binary from the NPM package).
To achieve this, use the ``pack`` application.
## Local Mode
- To prepare data from x-ray based methods, use:
The program ``lib/commonjs/servers/volume/pack`` (``volume-server-query`` in NPM package) can be used to query the data without running a http server.
```
node pack -xray main.ccp4 diff.ccp4 out.mdb
```
- For EM data, use:
```
node pack -em em.map out.mdb
```
Running the Server
------------------
- Install production dependencies:
```
npm install --only=production
```
- Update ``server-config.js`` to link to your data and optionally tweak the other parameters.
- Run it:
```
node server
```
In production it is a good idea to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
### Local Mode
The program ``local`` in the build folder can be used to query the data without running a http server.
- ``node local`` prints the program usage.
- ``node local jobs.json`` takes a list of jobs to execute in JSON format. A job entry is defined by this interface:
```TypeScript
interface JobEntry {
source: {
filename: string,
name: string,
id: string
},
query: {
kind: 'box' | 'cell',
space?: 'fractional' | 'cartesian',
bottomLeft?: number[],
topRight?: number[],
}
params: {
/** Determines the detail level as specified in server-config */
detail?: number,
/**
* Determines the sampling level:
* 1: Original data
* 2: Downsampled by factor 1/2
* ...
* N: downsampled 1/2^(N-1)
*/
forcedSamplingLevel?: number,
asBinary: boolean,
},
outputFolder: string
}
```
Example ``jobs.json`` file content:
```TypeScript
[{
source: {
filename: `g:/test/mdb/emd-8116.mdb`,
name: 'em',
id: '8116',
},
query: {
kind: 'cell'
},
params: {
detail: 4,
asBinary: true
},
outputFolder: 'g:/test/local-test'
}]
```
## Navigating the Source Code
@@ -79,8 +122,8 @@ The source code is split into 2 mains parts: ``pack`` and ``server``:
Consuming the Data
==================
The data can be consumed in any (modern) browser using the [ciftools library](https://github.com/molstar/ciftools) (or any other piece of code that can read text or binary CIF).
The data can be consumed in any (modern) browser using the [CIFTools.js library](https://github.com/dsehnal/CIFTools.js) (or any other piece of code that can read text or binary CIF).
The [Data Format](DataFormat.md) document gives a detailed description of the server response format.
As a reference/example of the server usage is available in Mol* ``mol-plugin`` module.
As a reference/example of the server usage, please see the implementation in [LiteMol](https://github.com/dsehnal/LiteMol) ([CIF.ts + Data.ts](https://github.com/dsehnal/LiteMol/tree/master/src/lib/Core/Formats/Density), [UI](https://github.com/dsehnal/LiteMol/tree/master/src/Viewer/Extensions/DensityStreaming)) or in Mol*.

47146
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "2.0.0-dev.2",
"version": "0.4.5",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -11,47 +11,27 @@
"url": "https://github.com/molstar/molstar/issues"
},
"scripts": {
"lint": "eslint .",
"lint-fix": "eslint . --fix",
"lint": "tslint src/**/*.ts",
"test": "npm run lint && jest",
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
"build-viewer": "npm run build-tsc && npm run build-extra && npm run build-webpack-viewer",
"build-tsc": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\"",
"build-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/",
"build-webpack": "webpack --mode production --config ./webpack.config.production.js",
"build-webpack-viewer": "webpack --mode production --config ./webpack.config.viewer.js",
"watch": "concurrently -c \"green,green,gray,gray\" --names \"tsc,srv,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-servers\" \"npm:watch-extra\" \"npm:watch-webpack\"",
"watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"",
"watch-viewer-debug": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer-debug\"",
"watch-tsc": "tsc --watch --incremental",
"watch-servers": "tsc --build tsconfig.commonjs.json --watch --incremental",
"watch-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/ --watch",
"build-tsc": "tsc",
"build-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/",
"build-webpack": "webpack --mode production",
"watch": "concurrently --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack\"",
"watch-tsc": "tsc -watch",
"watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/ --watch",
"watch-webpack": "webpack -w --mode development --display minimal",
"watch-webpack-viewer": "webpack -w --mode development --display errors-only --info-verbosity verbose --config ./webpack.config.viewer.js",
"watch-webpack-viewer-debug": "webpack -w --mode development --display errors-only --info-verbosity verbose --config ./webpack.config.viewer.debug.js",
"serve": "http-server -p 1338 -g",
"model-server": "node lib/commonjs/servers/model/server.js",
"model-server-watch": "nodemon --watch lib lib/commonjs/servers/model/server.js",
"volume-server-test": "node lib/commonjs/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
"plugin-state": "node lib/commonjs/servers/plugin-state/index.js --working-folder ./build/state --port 1339",
"serve": "http-server -p 1338",
"model-server": "node lib/servers/model/server.js",
"model-server-watch": "nodemon --watch lib lib/servers/model/server.js",
"volume-server": "node lib/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
"preversion": "npm run test",
"version": "npm run build",
"postversion": "git push && git push --tags"
"postversion": "git push && git push --tags",
"prepublishOnly": "npm run test && npm run build"
},
"files": [
"lib/",
"build/viewer/"
"lib/"
],
"bin": {
"cif2bcif": "lib/commonjs/cli/cif2bcif/index.js",
"cifschema": "lib/commonjs/cli/cifschema/index.js",
"model-server": "lib/commonjs/servers/model/server.js",
"model-server-query": "lib/commonjs/servers/model/query.js",
"model-server-preprocess": "lib/commonjs/servers/model/preprocess.js",
"volume-server": "lib/commonjs/servers/volume/server.js",
"volume-server-query": "lib/commonjs/servers/volume/query.js",
"volume-server-pack": "lib/commonjs/servers/volume/pack.js"
},
"nodemonConfig": {
"ignoreRoot": [
"./node_modules",
@@ -79,73 +59,59 @@
"contributors": [
"Alexander Rose <alexander.rose@weirdbyte.de>",
"David Sehnal <david.sehnal@gmail.com>",
"Sebastian Bittrich <sebastian.bittrich@rcsb.org>",
"Áron Samuel Kovács <aron.kovacs@mail.muni.cz>",
"Ludovic Autin <autin@scripps.edu>",
"Michal Malý <michal.maly@ibt.cas.cz>",
"Jiří Černý <jiri.cerny@ibt.cas.cz>"
"Sebastian Bittrich <sebastian.bittrich@rcsb.org>"
],
"license": "MIT",
"devDependencies": {
"@graphql-codegen/add": "^2.0.2",
"@graphql-codegen/cli": "^1.19.4",
"@graphql-codegen/time": "^2.0.2",
"@graphql-codegen/typescript": "^1.19.0",
"@graphql-codegen/typescript-graphql-files-modules": "^1.18.1",
"@graphql-codegen/typescript-graphql-request": "^2.0.3",
"@graphql-codegen/typescript-operations": "^1.17.12",
"@types/cors": "^2.8.8",
"@typescript-eslint/eslint-plugin": "^4.9.1",
"@typescript-eslint/parser": "^4.9.1",
"benchmark": "^2.1.4",
"concurrently": "^5.3.0",
"cpx2": "^3.0.0",
"css-loader": "^5.0.1",
"eslint": "^7.15.0",
"circular-dependency-plugin": "^5.2.0",
"concurrently": "^5.0.0",
"cpx": "^1.5.0",
"css-loader": "^3.2.0",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^6.2.0",
"fs-extra": "^9.0.1",
"graphql": "^15.4.0",
"http-server": "^0.12.3",
"jest": "^26.6.3",
"mini-css-extract-plugin": "^1.3.2",
"node-sass": "^5.0.0",
"raw-loader": "^4.0.2",
"sass-loader": "^10.1.0",
"simple-git": "^2.25.0",
"style-loader": "^2.0.0",
"ts-jest": "^26.4.4",
"typescript": "^4.1.2",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12",
"webpack-version-file-plugin": "^0.4.0"
"file-loader": "^4.2.0",
"fs-extra": "^8.1.0",
"graphql-code-generator": "^0.18.2",
"graphql-codegen-time": "^0.18.2",
"graphql-codegen-typescript-template": "^0.18.2",
"http-server": "^0.11.1",
"jest": "^24.9.0",
"jest-raw-loader": "^1.0.1",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.13.0",
"raw-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.1",
"typescript": "^3.7.2",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
},
"dependencies": {
"@types/argparse": "^1.0.38",
"@types/benchmark": "^2.1.0",
"@types/compression": "1.7.0",
"@types/express": "^4.17.9",
"@types/jest": "^26.0.18",
"@types/node": "^14.14.11",
"@types/node-fetch": "^2.5.7",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/swagger-ui-dist": "3.30.0",
"@types/argparse": "^1.0.36",
"@types/benchmark": "^1.0.31",
"@types/compression": "1.0.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",
"argparse": "^1.0.10",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.17.1",
"h264-mp4-encoder": "^1.0.12",
"immer": "^8.0.0",
"graphql": "^14.5.8",
"immutable": "^3.8.2",
"node-fetch": "^2.6.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"rxjs": "^6.6.3",
"swagger-ui-dist": "^3.37.2",
"tslib": "^2.0.3",
"util.promisify": "^1.0.1",
"node-fetch": "^2.6.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"rxjs": "^6.5.3",
"swagger-ui-dist": "^3.24.3",
"util.promisify": "^1.0.0",
"xhr2": "^0.2.0"
}
}

View File

@@ -4,40 +4,40 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
const git = require('simple-git');
const path = require('path');
const fs = require("fs");
const fse = require("fs-extra");
const git = require('simple-git')
const path = require('path')
const fs = require("fs")
const fse = require("fs-extra")
const remoteUrl = "https://github.com/molstar/molstar.github.io.git";
const buildDir = path.resolve(__dirname, '../build/');
const deployDir = path.resolve(buildDir, 'deploy/');
const localPath = path.resolve(deployDir, 'molstar.github.io/');
const remoteUrl = "https://github.com/molstar/molstar.github.io.git"
const buildDir = path.resolve(__dirname, '../build/')
const deployDir = path.resolve(buildDir, 'deploy/')
const localPath = path.resolve(deployDir, 'molstar.github.io/')
function log(command, stdout, stderr) {
if (command) {
console.log('\n###', command);
stdout.pipe(process.stdout);
stderr.pipe(process.stderr);
console.log('\n###', command)
stdout.pipe(process.stdout)
stderr.pipe(process.stderr)
}
}
function copyViewer() {
console.log('\n###', 'copy viewer files');
const viewerBuildPath = path.resolve(buildDir, '../build/viewer/');
const viewerDeployPath = path.resolve(localPath, 'viewer/');
fse.copySync(viewerBuildPath, viewerDeployPath, { overwrite: true });
console.log('\n###', 'copy viewer files')
const viewerBuildPath = path.resolve(buildDir, '../build/viewer/')
const viewerDeployPath = path.resolve(localPath, 'viewer/')
fse.copySync(viewerBuildPath, viewerDeployPath, { overwrite: true })
}
if (!fs.existsSync(localPath)) {
console.log('\n###', 'create localPath');
fs.mkdirSync(localPath, { recursive: true });
console.log('\n###', 'create localPath')
fs.mkdirSync(localPath, { recursive: true })
}
process.chdir(localPath);
if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
console.log('\n###', 'clone repository');
console.log('\n###', 'clone repository')
git()
.outputHandler(log)
.clone(remoteUrl, localPath)
@@ -45,9 +45,9 @@ if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
.exec(copyViewer)
.add(['-A'])
.commit('updated viewer')
.push();
.push()
} else {
console.log('\n###', 'update repository');
console.log('\n###', 'update repository')
git()
.outputHandler(log)
.fetch(['--all'])
@@ -55,5 +55,5 @@ if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
.exec(copyViewer)
.add(['-A'])
.commit('updated viewer')
.push();
.push()
}

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* 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 { CustomElementProperty } from '../../mol-model-props/common/custom-element-property';
@@ -10,21 +9,22 @@ import { Model, ElementIndex } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
export const StripedResidues = CustomElementProperty.create<number>({
label: 'Residue Stripes',
isStatic: true,
name: 'basic-wrapper-residue-striping',
display: 'Residue Stripes',
getData(model: Model) {
const map = new Map<ElementIndex, number>();
const residueIndex = model.atomicHierarchy.residueAtomSegments.index;
for (let i = 0, _i = model.atomicHierarchy.atoms._rowCount; i < _i; i++) {
map.set(i as ElementIndex, residueIndex[i] % 2);
}
return { value: map };
return map;
},
coloring: {
getColor(e) { return e === 0 ? Color(0xff0000) : Color(0x0000ff); },
getColor(e) { return e === 0 ? Color(0xff0000) : Color(0x0000ff) },
defaultColor: Color(0x777777)
},
getLabel(e) {
return e === 0 ? 'Odd stripe' : 'Even stripe';
format(e) {
return e === 0 ? 'Odd stripe' : 'Even stripe'
}
});
})

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { PluginUIComponent } from '../../mol-plugin/ui/base';
import * as React from 'react';
import { TransformUpdaterControl } from '../../mol-plugin/ui/state/update-transform';
export class BasicWrapperControls extends PluginUIComponent {
render() {
return <div style={{ overflowY: 'auto', display: 'block', height: '100%' }}>
<TransformUpdaterControl nodeRef='asm' />
<TransformUpdaterControl nodeRef='seq-visual' header={{ name: 'Sequence Visual' }} />
<TransformUpdaterControl nodeRef='het-visual' header={{ name: 'HET Visual' }} />
<TransformUpdaterControl nodeRef='water-visual' header={{ name: 'Water Visual' }} initiallyCollapsed={true} />
<TransformUpdaterControl nodeRef='ihm-visual' header={{ name: 'I/HM Visual' }} initiallyCollapsed={true} />
</div>;
}
}
export class CustomToastMessage extends PluginUIComponent {
render() {
return <>
Custom <i>Toast</i> content. No timeout.
</>;
}
}

View File

@@ -0,0 +1,94 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
import { PluginContext } from '../../mol-plugin/context';
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
import { StateTransforms } from '../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { StateBuilder } from '../../mol-state';
import Expression from '../../mol-script/language/expression';
import { BuiltInColorThemeName } from '../../mol-theme/color';
type SupportedFormats = 'cif' | 'pdb'
export namespace StateHelper {
export function download(b: StateBuilder.To<PSO.Root>, url: string, ref?: string) {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false }, { ref });
}
export function getModel(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, modelIndex = 0) {
const parsed = format === 'cif'
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
return parsed.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex });
}
export function structure(b: StateBuilder.To<PSO.Molecule.Model>) {
return b.apply(StateTransforms.Model.StructureFromModel, { tags: 'structure' })
};
export function selectChain(b: StateBuilder.To<PSO.Molecule.Structure>, auth_asym_id: string) {
const expression = MS.struct.generator.atomGroups({
'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), auth_asym_id])
})
return b.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: `Chain ${auth_asym_id}` });
}
export function select(b: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression) {
return b.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression });
}
export function selectSurroundingsOfFirstResidue(b: StateBuilder.To<PSO.Molecule.Structure>, comp_id: string, radius: number) {
const expression = MS.struct.modifier.includeSurroundings({
0: MS.struct.filter.first([
MS.struct.generator.atomGroups({
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
})
]),
radius
})
return b.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: `Surr. ${comp_id} (${radius} ang)` });
}
export function identityTransform(b: StateBuilder.To<PSO.Molecule.Structure>, m: Mat4) {
return b.apply(StateTransforms.Model.TransformStructureConformation,
{ axis: Vec3.create(1, 0, 0), angle: 0, translation: Vec3.zero() },
{ tags: 'transform' });
}
export function transform(b: StateBuilder.To<PSO.Molecule.Structure>, matrix: Mat4) {
return b.apply(StateTransforms.Model.TransformStructureConformationByMatrix, { matrix }, { tags: 'transform' });
}
export function assemble(b: StateBuilder.To<PSO.Molecule.Model>, id?: string) {
return b.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: id || 'deposited' }, { tags: 'asm' })
}
export function visual(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon'), { tags: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick'), { tags: 'het-visual' });
// visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
// .apply(StateTransforms.Representation.StructureRepresentation3D,
// StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 }), { tags: 'water-visual' });
return visualRoot;
}
export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression, coloring?: BuiltInColorThemeName) {
visualRoot
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', void 0, coloring), { tags: 'het-visual' });
return visualRoot;
}
}

View File

@@ -41,7 +41,7 @@
display: block;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
<link rel="stylesheet" type="text/css" href="app.css" />
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
@@ -50,18 +50,18 @@
<input type='text' id='url' placeholder='url' />
<input type='text' id='assemblyId' placeholder='assembly id' />
<select id='format'>
<option value='mmcif' selected>mmCIF</option>
<option value='cif' selected>CIF</option>
<option value='pdb'>PDB</option>
</select>
</div>
<div id="app"></div>
<script>
<script>
function $(id) { return document.getElementById(id); }
var pdbId = '1grm', assemblyId= '1';
var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
var format = 'mmcif';
var format = 'cif';
$('url').value = url;
$('url').onchange = function (e) { url = e.target.value; }
$('assemblyId').value = assemblyId;
@@ -69,8 +69,15 @@
$('format').value = format;
$('format').onchange = function (e) { format = e.target.value; }
// var url = 'https://www.ebi.ac.uk/pdbe/entry-files/pdb' + pdbId + '.ent';
// var format = 'pdb';
// var assemblyId = 'deposited';
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
BasicMolStarWrapper.setBackground(0xffffff);
// BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId });
// BasicMolStarWrapper.toggleSpin();
addControl('Load Asym Unit', () => BasicMolStarWrapper.load({ url: url, format: format }));
addControl('Load Assembly', () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId }));
@@ -79,14 +86,14 @@
addHeader('Camera');
addControl('Toggle Spin', () => BasicMolStarWrapper.toggleSpin());
addSeparator();
addHeader('Animation');
// adjust this number to make the animation faster or slower
// requires to "restart" the animation if changed
BasicMolStarWrapper.animate.modelIndex.targetFps = 30;
BasicMolStarWrapper.animate.modelIndex.maxFPS = 30;
addControl('Play To End', () => BasicMolStarWrapper.animate.modelIndex.onceForward());
addControl('Play To Start', () => BasicMolStarWrapper.animate.modelIndex.onceBackward());
@@ -97,7 +104,6 @@
addHeader('Misc');
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
addControl('Default Coloring', () => BasicMolStarWrapper.coloring.applyDefault());
addHeader('Interactivity');
addControl('Highlight seq_id=7', () => BasicMolStarWrapper.interactivity.highlightOn());
@@ -108,7 +114,7 @@
addControl('Static Superposition', () => BasicMolStarWrapper.tests.staticSuperposition());
addControl('Dynamic Superposition', () => BasicMolStarWrapper.tests.dynamicSuperposition());
addControl('Validation Tooltip', () => BasicMolStarWrapper.tests.toggleValidationTooltip());
addControl('Show Toasts', () => BasicMolStarWrapper.tests.showToasts());
addControl('Hide Toasts', () => BasicMolStarWrapper.tests.hideToasts());

View File

@@ -0,0 +1,201 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
import './index.html'
import { PluginContext } from '../../mol-plugin/context';
import { PluginCommands } from '../../mol-plugin/command';
import { StateTransforms } from '../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
import { Color } from '../../mol-util/color';
import { PluginStateObject as PSO, 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 { 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'
type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
class BasicWrapper {
plugin: PluginContext;
init(target: string | HTMLElement) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginSpec,
layout: {
initial: {
isExpanded: false,
showControls: false
},
controls: {
// left: 'none',
// right: BasicWrapperControls
}
}
});
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.Descriptor.name, StripedResidues.colorTheme!);
this.plugin.lociLabels.addProvider(StripedResidues.labelProvider);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider);
}
private download(b: StateBuilder.To<PSO.Root>, url: string) {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
}
private parse(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
const parsed = format === 'cif'
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
return parsed
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
.apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.Descriptor.name] }, { ref: 'props', state: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
}
private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: 'seq' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'), { ref: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'), { ref: 'het-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick', { alpha: 0.51 }), { ref: 'water-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill'), { ref: 'ihm-visual' });
return visualRoot;
}
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.dataState;
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
loadType = 'full';
} else if (this.loadedParams.url === url) {
if (state.select('asm').length > 0) loadType = 'update';
}
let tree: StateBuilder.Root;
if (loadType === 'full') {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
tree = state.build();
this.visual(this.parse(this.download(tree.toRoot(), url), format, assemblyId));
} else {
tree = state.build();
tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
this.loadedParams = { url, format, assemblyId };
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
}
setBackground(color: number) {
const renderer = this.plugin.canvas3d.props.renderer;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
}
toggleSpin() {
const trackball = this.plugin.canvas3d.props.trackball;
const spinning = trackball.spin;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
}
animate = {
modelIndex: {
maxFPS: 8,
onceForward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'forward' } } }) },
onceBackward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'backward' } } }) },
palindrome: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'palindrome', params: {} } }) },
loop: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'loop', params: {} } }) },
stop: () => this.plugin.state.animation.stop()
}
}
coloring = {
applyStripes: async () => {
const state = this.plugin.state.dataState;
const visuals = state.selectQ(q => q.ofTransformer(StateTransforms.Representation.StructureRepresentation3D));
const tree = state.build();
const colorTheme = { name: StripedResidues.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(StripedResidues.Descriptor.name).defaultValues };
for (const v of visuals) {
tree.to(v).update(old => ({ ...old, colorTheme }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
}
}
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;
const tree = buildStaticSuperposition(this.plugin, StaticSuperpositionTestData);
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: StateTransform.RootRef });
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
},
dynamicSuperposition: async () => {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.plugin.state.dataState, ref: StateTransform.RootRef });
await dynamicSuperpositionTest(this.plugin, ['1tqn', '2hhb', '4hhb'], 'HEM');
},
toggleValidationTooltip: async () => {
const state = this.plugin.state.behaviorState;
const tree = state.build().to(PDBeStructureQualityReport.id).update(PDBeStructureQualityReport, p => ({ ...p, showTooltip: !p.showTooltip }));
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
},
showToasts: () => {
PluginCommands.Toast.Show.dispatch(this.plugin, {
title: 'Toast 1',
message: 'This is an example text, timeout 3s',
key: 'toast-1',
timeoutMs: 3000
});
PluginCommands.Toast.Show.dispatch(this.plugin, {
title: 'Toast 2',
message: CustomToastMessage,
key: 'toast-2'
});
},
hideToasts: () => {
PluginCommands.Toast.Hide.dispatch(this.plugin, { key: 'toast-1' });
PluginCommands.Toast.Hide.dispatch(this.plugin, { key: 'toast-2' });
}
}
}
(window as any).BasicMolStarWrapper = new BasicWrapper();

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
// TODO: move to an "example"
import { PluginContext } from '../../mol-plugin/context';
import { Mat4 } from '../../mol-math/linear-algebra';
import { StateHelper } from './helpers';
import { PluginCommands } from '../../mol-plugin/command';
import { StateSelection, StateBuilder } from '../../mol-state';
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { compile } from '../../mol-script/runtime/query/compiler';
import { StructureSelection, QueryContext } from '../../mol-model/structure';
import { superposeStructures } from '../../mol-model/structure/structure/util/superposition';
import Expression from '../../mol-script/language/expression';
export type SuperpositionTestInput = {
pdbId: string,
auth_asym_id: string,
matrix: Mat4
}[];
// function getAxisAngleTranslation(m: Mat4) {
// const translation = Mat4.getTranslation(Vec3.zero(), m);
// const axis = Vec3.zero();
// const angle = 180 / Math.PI * Quat.getAxisAngle(axis, Mat4.getRotation(Quat.zero(), m));
// return { translation, axis, angle };
// }
export function buildStaticSuperposition(ctx: PluginContext, src: SuperpositionTestInput) {
const b = ctx.state.dataState.build().toRoot();
for (const s of src) {
StateHelper.visual(ctx,
StateHelper.transform(
StateHelper.selectChain(
StateHelper.structure(
StateHelper.getModel(StateHelper.download(b, `https://www.ebi.ac.uk/pdbe/static/entry/${s.pdbId}_updated.cif`), 'cif')),
s.auth_asym_id
),
s.matrix
)
);
}
return b;
}
export const StaticSuperpositionTestData: SuperpositionTestInput = [
{ pdbId: '1aj5', auth_asym_id: 'A', matrix: Mat4.identity() },
{ pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows(
[[0.406, 0.879, 0.248, -200.633],
[0.693, -0.473, 0.544, 73.403],
[0.596, -0.049, -0.802, -14.209],
[0, 0, 0, 1]] )},
{ pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows(
[[-0.053, -0.077, 0.996, -45.633],
[-0.312, 0.949, 0.057, -12.255],
[-0.949, -0.307, -0.074, 53.562],
[0, 0, 0, 1]] )}
];
export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[], comp_id: string) {
const state = ctx.state.dataState;
const structures = state.build().toRoot();
for (const s of src) {
StateHelper.structure(
StateHelper.getModel(StateHelper.download(structures, `https://www.ebi.ac.uk/pdbe/static/entry/${s}_updated.cif`), 'cif'));
}
await PluginCommands.State.Update.dispatch(ctx, { state, tree: structures });
const pivot = MS.struct.filter.first([
MS.struct.generator.atomGroups({
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
})
]);
const rest = MS.struct.modifier.exceptBy({
0: MS.struct.generator.all(),
by: pivot
});
const query = compile<StructureSelection>(pivot);
const xs = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure));
const selections = xs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.obj!.data))));
const transforms = superposeStructures(selections);
const visuals = state.build();
siteVisual(ctx, StateHelper.selectSurroundingsOfFirstResidue(visuals.to(xs[0].transform.ref), 'HEM', 7), pivot, rest);
for (let i = 1; i < selections.length; i++) {
const root = visuals.to(xs[i].transform.ref);
siteVisual(ctx,
StateHelper.transform(StateHelper.selectSurroundingsOfFirstResidue(root, 'HEM', 7), transforms[i - 1].bTransform),
pivot, rest);
}
await PluginCommands.State.Update.dispatch(ctx, { state, tree: visuals });
}
function siteVisual(ctx: PluginContext, b: StateBuilder.To<PSO.Molecule.Structure>, pivot: Expression, rest: Expression) {
StateHelper.ballsAndSticks(ctx, b, pivot, 'residue-name');
StateHelper.ballsAndSticks(ctx, b, rest, 'uniform');
}

View File

@@ -0,0 +1,252 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse'
import * as util from 'util'
import * as path from 'path'
import * as fs from 'fs'
import * as zlib from 'zlib'
import fetch from 'node-fetch'
require('util.promisify').shim()
const readFile = util.promisify(fs.readFile)
const writeFile = util.promisify(fs.writeFile)
import { Progress } from '../../mol-task'
import { Database, Table, DatabaseCollection } from '../../mol-data/db'
import { CIF } from '../../mol-io/reader/cif'
import { CifWriter } from '../../mol-io/writer/cif'
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd'
import { SetUtils } from '../../mol-util/set'
import { DefaultMap } from '../../mol-util/map'
import { mmCIF_chemCompBond_schema } from '../../mol-io/reader/cif/schema/mmcif-extras';
export async function ensureAvailable(path: string, url: string) {
if (FORCE_DOWNLOAD || !fs.existsSync(path)) {
console.log(`downloading ${url}...`)
const data = await fetch(url)
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR);
}
if (url.endsWith('.gz')) {
await writeFile(path, zlib.gunzipSync(await data.buffer()))
} else {
await writeFile(path, await data.text())
}
console.log(`done downloading ${url}`)
}
}
export async function ensureDataAvailable() {
await ensureAvailable(CCD_PATH, CCD_URL)
await ensureAvailable(PVCD_PATH, PVCD_URL)
}
export async function readFileAsCollection<S extends Database.Schema>(path: string, schema: S) {
const parsed = await parseCif(await readFile(path, 'utf8'))
return CIF.toDatabaseCollection(schema, parsed.result)
}
export async function readCCD() {
return readFileAsCollection(CCD_PATH, CCD_Schema)
}
export async function readPVCD() {
return readFileAsCollection(PVCD_PATH, CCD_Schema)
}
async function parseCif(data: string | Uint8Array) {
const comp = CIF.parse(data);
console.time('parse cif');
const parsed = await comp.run(p => console.log(Progress.format(p)), 250);
console.timeEnd('parse cif');
if (parsed.isError) throw parsed;
return parsed
}
export function getEncodedCif(name: string, database: Database<Database.Schema>, binary = false) {
const encoder = CifWriter.createEncoder({ binary, encoderName: 'mol*' });
CifWriter.Encoder.writeDatabase(encoder, name, database)
return encoder.getData();
}
type CCB = Table<CCD_Schema['chem_comp_bond']>
type CCA = Table<CCD_Schema['chem_comp_atom']>
function ccbKey(compId: string, atomId1: string, atomId2: string) {
return atomId1 < atomId2 ? `${compId}:${atomId1}-${atomId2}` : `${compId}:${atomId2}-${atomId1}`
}
function addChemCompBondToSet(set: Set<string>, ccb: CCB) {
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
set.add(ccbKey(ccb.comp_id.value(i), ccb.atom_id_1.value(i), ccb.atom_id_2.value(i)))
}
return set
}
function addChemCompAtomToSet(set: Set<string>, cca: CCA) {
for (let i = 0, il = cca._rowCount; i < il; ++i) {
set.add(cca.atom_id.value(i))
}
return set
}
function checkAddingBondsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
const ccbSetByParent = DefaultMap<string, Set<string>>(() => new Set())
for (const k in pvcd) {
const { chem_comp, chem_comp_bond } = pvcd[k]
if (chem_comp_bond._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0)
if (parentIds.length === 0) {
const set = ccbSetByParent.getDefault(chem_comp.id.value(0))
addChemCompBondToSet(set, chem_comp_bond)
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
const parentId = parentIds[i]
const set = ccbSetByParent.getDefault(parentId)
addChemCompBondToSet(set, chem_comp_bond)
}
}
}
}
for (const k in pvcd) {
const { chem_comp, chem_comp_atom, chem_comp_bond } = pvcd[k]
if (chem_comp_bond._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0)
if (parentIds.length > 0) {
for (let i = 0, il = parentIds.length; i < il; ++i) {
const entryBonds = addChemCompBondToSet(new Set<string>(), chem_comp_bond)
const entryAtoms = addChemCompAtomToSet(new Set<string>(), chem_comp_atom)
const extraBonds = SetUtils.difference(ccbSetByParent.get(parentIds[i])!, entryBonds)
extraBonds.forEach(bk => {
const [a1, a2] = bk.split('|')
if (entryAtoms.has(a1) && entryAtoms.has(a2)) {
console.error(`Adding all PVCD bonds would wrongly add bond ${bk} for ${k}`)
}
})
}
}
}
}
}
async function createBonds() {
await ensureDataAvailable()
const ccd = await readCCD()
const pvcd = await readPVCD()
const ccbSet = new Set<string>()
const comp_id: string[] = []
const atom_id_1: string[] = []
const atom_id_2: string[] = []
const value_order: string[] = []
const pdbx_aromatic_flag: string[] = []
const pdbx_stereo_config: string[] = []
const molstar_protonation_variant: string[] = []
function addBonds(compId: string, ccb: CCB, protonationVariant: boolean) {
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
const atomId1 = ccb.atom_id_1.value(i)
const atomId2 = ccb.atom_id_2.value(i)
const k = ccbKey(compId, atomId1, atomId2)
if (!ccbSet.has(k)) {
atom_id_1.push(atomId1)
atom_id_2.push(atomId2)
comp_id.push(compId)
value_order.push(ccb.value_order.value(i))
pdbx_aromatic_flag.push(ccb.pdbx_aromatic_flag.value(i))
pdbx_stereo_config.push(ccb.pdbx_stereo_config.value(i))
molstar_protonation_variant.push(protonationVariant ? 'Y' : 'N')
ccbSet.add(k)
}
}
}
// check adding bonds from PVCD
checkAddingBondsFromPVCD(pvcd)
// add bonds from PVCD
for (const k in pvcd) {
const { chem_comp, chem_comp_bond } = pvcd[k]
if (chem_comp_bond._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0)
if (parentIds.length === 0) {
addBonds(chem_comp.id.value(0), chem_comp_bond, false)
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
addBonds(parentIds[i], chem_comp_bond, true)
}
}
}
}
// add bonds from CCD
for (const k in ccd) {
const { chem_comp, chem_comp_bond } = ccd[k]
if (chem_comp_bond._rowCount) {
addBonds(chem_comp.id.value(0), chem_comp_bond, false)
}
}
const bondTable = Table.ofArrays(mmCIF_chemCompBond_schema, {
comp_id, atom_id_1, atom_id_2, value_order,
pdbx_aromatic_flag, pdbx_stereo_config, molstar_protonation_variant
})
const bondDatabase = Database.ofTables(
TABLE_NAME,
{ chem_comp_bond: mmCIF_chemCompBond_schema },
{ chem_comp_bond: bondTable }
)
return bondDatabase
}
async function run(out: string, binary = false) {
const bonds = await createBonds()
const cif = getEncodedCif(TABLE_NAME, bonds, binary)
if (!fs.existsSync(path.dirname(out))) {
fs.mkdirSync(path.dirname(out));
}
writeFile(out, cif)
}
const TABLE_NAME = 'CHEM_COMP_BONDS'
const DATA_DIR = path.join(__dirname, '..', '..', '..', 'build/data')
const CCD_PATH = path.join(DATA_DIR, 'components.cif')
const PVCD_PATH = path.join(DATA_DIR, 'aa-variants-v1.cif')
const CCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif'
const PVCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/aa-variants-v1.cif'
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Create a cif file with one big table of all chem_comp_bond entries from the CCD and PVCD.'
});
parser.addArgument('out', {
help: 'Generated file output path.'
});
parser.addArgument([ '--forceDownload', '-f' ], {
action: 'storeTrue',
help: 'Force download of CCD and PVCD.'
});
parser.addArgument([ '--binary', '-b' ], {
action: 'storeTrue',
help: 'Output as BinaryCIF.'
});
interface Args {
out: string
forceDownload?: boolean
binary?: boolean
}
const args: Args = parser.parseArgs();
const FORCE_DOWNLOAD = args.forceDownload
run(args.out, args.binary)

View File

@@ -38,16 +38,16 @@
display: block;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
<link rel="stylesheet" type="text/css" href="app.css" />
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
<div id='controls'></div>
<div id="app"></div>
<script>
<script>
LightingDemo.init('app')
LightingDemo.load({ url: 'https://files.rcsb.org/download/1M07.cif', assemblyId: '1' })
addHeader('Example PDB IDs');
addControl('1M07', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/1M07.cif', assemblyId: '1' }));
addControl('6HY0', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/6HY0.cif', assemblyId: '1' }));

View File

@@ -0,0 +1,166 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { createPlugin, DefaultPluginSpec } from '../../../mol-plugin';
import './index.html'
import { PluginContext } from '../../../mol-plugin/context';
import { PluginCommands } from '../../../mol-plugin/command';
import { StateTransforms } from '../../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/transforms/representation';
import { PluginStateObject as PSO } from '../../../mol-plugin/state/objects';
import { StateBuilder } from '../../../mol-state';
import { Canvas3DProps } from '../../../mol-canvas3d/canvas3d';
require('mol-plugin/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb'
type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
const Canvas3DPresets = {
illustrative: {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusionEnable: true,
occlusionBias: 0.8,
occlusionKernelSize: 6,
outlineEnable: true,
},
renderer: {
ambientIntensity: 1,
lightIntensity: 0,
}
},
occlusion: {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusionEnable: true,
occlusionBias: 0.8,
occlusionKernelSize: 6,
outlineEnable: false,
},
renderer: {
ambientIntensity: 0.4,
lightIntensity: 0.6,
}
},
standard: {
multiSample: {
mode: 'off' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusionEnable: false,
outlineEnable: false,
},
renderer: {
ambientIntensity: 0.4,
lightIntensity: 0.6,
}
}
}
type Canvas3DPreset = keyof typeof Canvas3DPresets
function getPreset(preset: Canvas3DPreset) {
switch (preset) {
case 'illustrative': return Canvas3DPresets['illustrative']
case 'standard': return Canvas3DPresets['standard']
case 'occlusion': return Canvas3DPresets['occlusion']
}
}
class LightingDemo {
plugin: PluginContext;
init(target: string | HTMLElement) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginSpec,
layout: {
initial: {
isExpanded: false,
showControls: false
},
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' }
}
});
this.setPreset('illustrative');
}
setPreset(preset: Canvas3DPreset) {
const props = getPreset(preset)
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: {
...props,
multiSample: {
...this.plugin.canvas3d.props.multiSample,
...props.multiSample
},
renderer: {
...this.plugin.canvas3d.props.renderer,
...props.renderer
},
postprocessing: {
...this.plugin.canvas3d.props.postprocessing,
...props.postprocessing
},
}});
}
private download(b: StateBuilder.To<PSO.Root>, url: string) {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
}
private parse(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
const parsed = format === 'cif'
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
return parsed
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
}
private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill', {}, 'illustrative'), { ref: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'), { ref: 'het-visual' });
return visualRoot;
}
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.dataState;
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
loadType = 'full';
} else if (this.loadedParams.url === url) {
if (state.select('asm').length > 0) loadType = 'update';
}
let tree: StateBuilder.Root;
if (loadType === 'full') {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
tree = state.build();
this.visual(this.parse(this.download(tree.toRoot(), url), format, assemblyId));
} else {
tree = state.build();
tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
this.loadedParams = { url, format, assemblyId };
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
}
}
(window as any).LightingDemo = new LightingDemo();

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<title>Mol* Docking Viewer</title>
<style>
#app {
position: absolute;
left: 100px;
top: 100px;
width: 800px;
height: 600px;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./molstar.js"></script>
<script type="text/javascript">
var viewer = new DockingViewer('app', [0x33DD22, 0x1133EE], true);
function getParam(name, regex) {
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
}
var pdbqt = getParam('pdbqt', '[^&]+').trim();
var mol2 = getParam('mol2', '[^&]+').trim();
viewer.loadStructuresFromUrlsAndMerge([
{ url: pdbqt, format: 'pdbqt' },
{ url: mol2, format: 'mol2' }
]);
</script>
</body>
</html>

View File

@@ -1,213 +0,0 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import '../../mol-util/polyfill';
import { createPlugin } from '../../mol-plugin';
import { DefaultPluginSpec } from '../../mol-plugin/spec';
import './index.html';
import { PluginContext } from '../../mol-plugin/context';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginSpec } from '../../mol-plugin/spec';
import { PluginConfig } from '../../mol-plugin/config';
import { ObjectKeys } from '../../mol-util/type-helpers';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { Structure } from '../../mol-model/structure';
import { PluginStateTransform, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Task } from '../../mol-task';
import { StateObject } from '../../mol-state';
import { ViewportComponent, StructurePreset, ShowButtons } from './viewport';
import { PluginBehaviors } from '../../mol-plugin/behavior';
import { ColorNames } from '../../mol-util/color/names';
import { Color } from '../../mol-util/color';
require('mol-plugin-ui/skin/light.scss');
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setProductionMode, setDebugMode } from '../../mol-util/debug';
const DefaultViewerOptions = {
extensions: ObjectKeys({}),
layoutIsExpanded: true,
layoutShowControls: true,
layoutShowRemoteState: true,
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
layoutShowSequence: true,
layoutShowLog: true,
layoutShowLeftPanel: true,
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
};
class Viewer {
plugin: PluginContext
constructor(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
const o = { ...DefaultViewerOptions, ...{
layoutIsExpanded: false,
layoutShowControls: false,
layoutShowRemoteState: false,
layoutShowSequence: true,
layoutShowLog: false,
layoutShowLeftPanel: true,
viewportShowExpand: true,
viewportShowControls: false,
viewportShowSettings: false,
viewportShowSelectionMode: false,
viewportShowAnimation: false,
} };
const defaultSpec = DefaultPluginSpec();
const spec: PluginSpec = {
actions: [...defaultSpec.actions],
behaviors: [
PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci, { mark: false }),
PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci),
PluginSpec.Behavior(PluginBehaviors.CustomProps.StructureInfo),
PluginSpec.Behavior(PluginBehaviors.CustomProps.Interactions),
PluginSpec.Behavior(PluginBehaviors.CustomProps.SecondaryStructure),
],
animations: [...defaultSpec.animations || []],
customParamEditors: defaultSpec.customParamEditors,
layout: {
initial: {
isExpanded: o.layoutIsExpanded,
showControls: o.layoutShowControls,
controlsDisplay: o.layoutControlsDisplay,
},
controls: {
...defaultSpec.layout && defaultSpec.layout.controls,
top: o.layoutShowSequence ? undefined : 'none',
bottom: o.layoutShowLog ? undefined : 'none',
left: o.layoutShowLeftPanel ? undefined : 'none',
}
},
components: {
...defaultSpec.components,
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
viewport: {
view: ViewportComponent
}
},
config: [
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
[PluginConfig.State.DefaultServer, o.pluginStateServer],
[PluginConfig.State.CurrentServer, o.pluginStateServer],
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
[ShowButtons, showButtons]
]
};
const element = typeof elementOrId === 'string'
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
this.plugin = createPlugin(element, spec);
(this.plugin.customState as any) = {
colorPalette: {
name: 'colors',
params: { list: { colors } }
}
};
this.plugin.behaviors.canvas3d.initialized.subscribe(v => {
if (v) {
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
renderer: {
...this.plugin.canvas3d!.props.renderer,
backgroundColor: ColorNames.white,
},
camera: {
...this.plugin.canvas3d!.props.camera,
helper: { axes: { name: 'off', params: {} } }
}
} });
}
});
}
async loadStructuresFromUrlsAndMerge(sources: { url: string, format: BuiltInTrajectoryFormat, isBinary?: boolean }[]) {
const structures: { ref: string }[] = [];
for (const { url, format, isBinary } of sources) {
const data = await this.plugin.builders.data.download({ url, isBinary });
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
const model = await this.plugin.builders.structure.createModel(trajectory);
const modelProperties = await this.plugin.builders.structure.insertModelProperties(model);
const structure = await this.plugin.builders.structure.createStructure(modelProperties || model);
const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
structures.push({ ref: structureProperties?.ref || structure.ref });
}
// remove current structuresfrom hierarchy as they will be merged
// TODO only works with using loadStructuresFromUrlsAndMerge once
// need some more API metho to work with the hierarchy
this.plugin.managers.structure.hierarchy.updateCurrent(this.plugin.managers.structure.hierarchy.current.structures, 'remove');
const dependsOn = structures.map(({ ref }) => ref);
const data = this.plugin.state.data.build().toRoot().apply(MergeStructures, { structures }, { dependsOn });
const structure = await data.commit();
const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
this.plugin.behaviors.canvas3d.initialized.subscribe(async v => {
await this.plugin.builders.structure.representation.applyPreset(structureProperties || structure, StructurePreset);
});
}
}
type MergeStructures = typeof MergeStructures
const MergeStructures = PluginStateTransform.BuiltIn({
name: 'merge-structures',
display: { name: 'Merge Structures', description: 'Merge Structure' },
from: PSO.Root,
to: PSO.Molecule.Structure,
params: {
structures: PD.ObjectList({
ref: PD.Text('')
}, ({ ref }) => ref, { isHidden: true })
}
})({
apply({ params, dependencies }) {
return Task.create('Merge Structures', async ctx => {
if (params.structures.length === 0) return StateObject.Null;
const first = dependencies![params.structures[0].ref].data as Structure;
const builder = Structure.Builder({ masterModel: first.models[0] });
for (const { ref } of params.structures) {
const s = dependencies![ref].data as Structure;
for (const unit of s.units) {
// TODO invariantId
builder.addUnit(unit.kind, unit.model, unit.conformation.operator, unit.elements, unit.traits);
}
}
const structure = builder.getStructure();
return new PSO.Molecule.Structure(structure, { label: 'Merged Structure' });
});
}
});
(window as any).DockingViewer = Viewer;
export { Viewer as DockingViewer };

View File

@@ -1,276 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react';
import { PluginUIComponent } from '../../mol-plugin-ui/base';
import { Viewport, ViewportControls } from '../../mol-plugin-ui/viewport';
import { BackgroundTaskProgress } from '../../mol-plugin-ui/task';
import { LociLabels } from '../../mol-plugin-ui/controls';
import { Toasts } from '../../mol-plugin-ui/toast';
import { Button } from '../../mol-plugin-ui/controls/common';
import { StructureRepresentationPresetProvider, presetStaticComponent } from '../../mol-plugin-state/builder/structure/representation-preset';
import { StateObjectRef } from '../../mol-state';
import { StructureSelectionQueries, StructureSelectionQuery } from '../../mol-plugin-state/helpers/structure-selection-query';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { InteractionsRepresentationProvider } from '../../mol-model-props/computed/representations/interactions';
import { InteractionTypeColorThemeProvider } from '../../mol-model-props/computed/themes/interaction-type';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginContext } from '../../mol-plugin/context';
import { StructureRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
import { Color } from '../../mol-util/color';
import { PluginConfig } from '../../mol-plugin/config';
function shinyStyle(plugin: PluginContext) {
return PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
renderer: {
...plugin.canvas3d!.props.renderer,
style: { name: 'plastic', params: {} },
},
postprocessing: {
...plugin.canvas3d!.props.postprocessing,
occlusion: { name: 'off', params: {} },
outline: { name: 'off', params: {} }
}
} });
}
function occlusionStyle(plugin: PluginContext) {
return PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
renderer: {
...plugin.canvas3d!.props.renderer,
style: { name: 'flat', params: {} }
},
postprocessing: {
...plugin.canvas3d!.props.postprocessing,
occlusion: { name: 'on', params: {
samples: 64,
radius: 8,
bias: 1.0,
blurKernelSize: 13
} },
outline: { name: 'on', params: {
scale: 1.0,
threshold: 0.33
} }
}
} });
}
const ligandPlusSurroundings = StructureSelectionQuery('Surrounding Residues (5 \u212B) of Ligand plus Ligand itself', MS.struct.modifier.union([
MS.struct.modifier.includeSurroundings({
0: StructureSelectionQueries.ligand.expression,
radius: 5,
'as-whole-residues': true
})
]));
const ligandSurroundings = StructureSelectionQuery('Surrounding Residues (5 \u212B) of Ligand', MS.struct.modifier.union([
MS.struct.modifier.exceptBy({
0: ligandPlusSurroundings.expression,
by: StructureSelectionQueries.ligand.expression
})
]));
const PresetParams = {
...StructureRepresentationPresetProvider.CommonParams,
};
export const StructurePreset = StructureRepresentationPresetProvider({
id: 'preset-structure',
display: { name: 'Structure' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
if (!structureCell) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
polymer: await presetStaticComponent(plugin, structureCell, 'polymer'),
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.35 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams }, color: 'chain-id', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }),
};
await update.commit({ revertOnError: true });
await shinyStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'residue' });
return { components, representations };
}
});
export const IllustrativePreset = StructureRepresentationPresetProvider({
id: 'preset-illustrative',
display: { name: 'Illustrative' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
if (!structureCell) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
polymer: await presetStaticComponent(plugin, structureCell, 'polymer'),
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'spacefill', typeParams: { ...typeParams }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
polymer: builder.buildRepresentation(update, components.polymer, { type: 'spacefill', typeParams: { ...typeParams }, color: 'illustrative', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }),
};
await update.commit({ revertOnError: true });
await occlusionStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'residue' });
return { components, representations };
}
});
const SurfacePreset = StructureRepresentationPresetProvider({
id: 'preset-surface',
display: { name: 'Surface' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
polymer: await presetStaticComponent(plugin, structureCell, 'polymer'),
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
polymer: builder.buildRepresentation(update, components.polymer, { type: 'molecular-surface', typeParams: { ...typeParams, quality: 'custom', resolution: 0.5, doubleSided: true }, color: 'partial-charge' }, { tag: 'polymer' }),
};
await update.commit({ revertOnError: true });
await shinyStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'residue' });
return { components, representations };
}
});
const PocketPreset = StructureRepresentationPresetProvider({
id: 'preset-pocket',
display: { name: 'Pocket' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
surroundings: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandSurroundings, `surroundings`),
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
surroundings: builder.buildRepresentation(update, components.surroundings, { type: 'molecular-surface', typeParams: { ...typeParams, includeParent: true, quality: 'custom', resolution: 0.2, doubleSided: true }, color: 'partial-charge' }, { tag: 'surroundings' }),
};
await update.commit({ revertOnError: true });
await shinyStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'element' });
return { components, representations };
}
});
const InteractionsPreset = StructureRepresentationPresetProvider({
id: 'preset-interactions',
display: { name: 'Interactions' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
surroundings: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandSurroundings, `surroundings`),
interactions: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandPlusSurroundings, `interactions`)
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.3 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
ballAndStick: builder.buildRepresentation(update, components.surroundings, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.1, sizeAspectRatio: 1 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ball-and-stick' }),
interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }),
label: builder.buildRepresentation(update, components.surroundings, { type: 'label', typeParams: { ...typeParams, background: false, borderWidth: 0.1 }, color: 'uniform', colorParams: { value: Color(0x000000) } }, { tag: 'label' }),
};
await update.commit({ revertOnError: true });
await shinyStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'element' });
return { components, representations };
}
});
export const ShowButtons = PluginConfig.item('showButtons', true);
export class ViewportComponent extends PluginUIComponent {
async _set(structures: readonly StructureRef[], preset: StructureRepresentationPresetProvider) {
await this.plugin.managers.structure.component.clear(structures);
await this.plugin.managers.structure.component.applyPreset(structures, preset);
}
set = async (preset: StructureRepresentationPresetProvider) => {
await this._set(this.plugin.managers.structure.hierarchy.selection.structures, preset);
}
structurePreset = () => this.set(StructurePreset);
illustrativePreset = () => this.set(IllustrativePreset);
surfacePreset = () => this.set(SurfacePreset);
pocketPreset = () => this.set(PocketPreset);
interactionsPreset = () => this.set(InteractionsPreset);
get showButtons () {
return this.plugin.config.get(ShowButtons);
}
render() {
const VPControls = this.plugin.spec.components?.viewport?.controls || ViewportControls;
return <>
<Viewport />
{this.showButtons && <div className='msp-viewport-top-left-controls'>
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.structurePreset} >Structure</Button>
</div>
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.illustrativePreset}>Illustrative</Button>
</div>
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.surfacePreset}>Surface</Button>
</div>
{/* <div style={{ marginBottom: '4px' }}>
<Button onClick={this.pocketPreset}>Pocket</Button>
</div> */}
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.interactionsPreset}>Interactions</Button>
</div>
</div>}
<VPControls />
<BackgroundTaskProgress />
<div className='msp-highlight-toast-wrapper'>
<LociLabels />
<Toasts />
</div>
</>;
}
}

View File

@@ -4,12 +4,12 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Table } from '../../mol-data/db';
import { CifWriter } from '../../mol-io/writer/cif';
import * as S from './schemas';
import { Table } from '../../mol-data/db'
import { CifWriter } from '../../mol-io/writer/cif'
import * as S from './schemas'
// import { getCategoryInstanceProvider } from './utils'
export function createMapping(allData: any) {
export default function create(allData: any) {
const mols = Object.keys(allData);
const enc = CifWriter.createEncoder();
enc.startDataBlock(mols[0]);

View File

@@ -4,21 +4,21 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Column } from '../../mol-data/db';
import { Column } from '../../mol-data/db'
import Type = Column.Schema
export const Sources = {
id: Type.str,
count: Type.int
};
}
export type Sources = typeof Sources
export const Base = {
id: Type.str,
identifier: Type.str,
mapping_group_id: Type.int
};
}
export type Base = typeof Base
export const mapping = {
@@ -36,17 +36,17 @@ export const mapping = {
end_label_seq_id: Type.int,
end_auth_seq_id: Type.int,
pdbx_end_PDB_ins_code: Type.str
};
}
export type mapping = typeof mapping
export const Pfam = {
description: Type.str
};
}
export type Pfam = typeof Pfam
export const InterPro = {
name: Type.str
};
}
export type InterPro = typeof InterPro
export const CATH = {
@@ -56,32 +56,32 @@ export const CATH = {
identifier: Type.str,
class: Type.str,
topology: Type.str,
};
}
export type CATH = typeof CATH
export const EC = {
accepted_name: Type.str,
reaction: Type.str,
systematic_name: Type.str
};
}
export type EC = typeof EC
export const UniProt = {
name: Type.str
};
}
export type UniProt = typeof UniProt
export const SCOP = {
sccs: Type.str,
description: Type.str
};
}
export type SCOP = typeof SCOP
export const GO = {
category: Type.str,
definition: Type.str,
name: Type.str
};
}
export type GO = typeof GO
export const categories = {
@@ -92,4 +92,4 @@ export const categories = {
UniProt,
SCOP,
GO
};
}

View File

@@ -4,9 +4,9 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import express from 'express';
import fetch from 'node-fetch';
import { createMapping } from './mapping';
import * as express from 'express'
import fetch from 'node-fetch'
import createMapping from './mapping'
async function getMappings(id: string) {
const data = await fetch(`https://www.ebi.ac.uk/pdbe/api/mappings/${id}`);
@@ -19,7 +19,7 @@ let PORT = process.env.port || 1338;
const app = express();
const PREFIX = '/';
const PREFIX = '/'
app.get(`${PREFIX}/:id`, async (req, res) => {
try {
@@ -41,7 +41,7 @@ app.get(`${PREFIX}/:id`, async (req, res) => {
app.get(`${PREFIX}`, (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Usage: /pdb_id, e.g. /1tqn');
});
})
app.listen(PORT);

View File

@@ -4,8 +4,8 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import fetch from 'node-fetch';
import { createMapping } from './mapping';
import fetch from 'node-fetch'
import createMapping from './mapping'
(async function () {
const data = await fetch('https://www.ebi.ac.uk/pdbe/api/mappings/1tqn?pretty=true');

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<title>Mol* ModelServer Query Builder</title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./index.js"></script>
</body>
</html>

View File

@@ -0,0 +1,134 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import * as Rx from 'rxjs'
import { QueryDefinition, QueryList } from '../../servers/model/server/api'
import './index.html'
interface State {
query: Rx.BehaviorSubject<QueryDefinition>,
id: Rx.BehaviorSubject<string>,
params: Rx.BehaviorSubject<any>,
isBinary: Rx.BehaviorSubject<boolean>,
models: Rx.BehaviorSubject<number[]>,
url: Rx.Subject<string>
}
class Root extends React.Component<{ state: State }, { }> {
render() {
return <div>
<div>
Query: <QuerySelect state={this.props.state} />
</div>
<div>
ID: <input type='text' onChange={t => this.props.state.id.next(t.currentTarget.value)} />
</div>
<div>
Params:<br/>
<QueryParams state={this.props.state} />
</div>
<div>
Model numbers (empty for all): <ModelNums state={this.props.state} />
</div>
<div>
<input type='checkbox' onChange={t => this.props.state.isBinary.next(!!t.currentTarget.checked)} /> Binary
</div>
<div>
Query string:
<QueryUrl state={this.props.state} />
</div>
</div>
}
}
class QuerySelect extends React.Component<{ state: State }> {
render() {
return <select onChange={s => this.props.state.query.next(QueryList[+s.currentTarget.value].definition)}>
{ QueryList.map((q, i) => <option value={i} key={i} selected={i === 1}>{q.definition.niceName}</option>) }
</select>
}
}
class QueryParams extends React.Component<{ state: State }, { prms: string }> {
state = { prms: '' };
parseParams(str: string) {
this.setState({ prms: str });
try {
const params = JSON.parse(str);
this.props.state.params.next(params);
} catch {
this.props.state.params.next({});
}
}
componentDidMount() {
this.props.state.query.subscribe(q => this.setState({ prms: formatParams(q) }))
}
render() {
return <textarea style={{height: '300px'}} value={this.state.prms} cols={80} onChange={t => this.parseParams(t.currentTarget.value)} />;
}
}
class QueryUrl extends React.Component<{ state: State }, { queryString: string }> {
state = { queryString: '' };
componentDidMount() {
this.props.state.url.subscribe(url => this.setState({ queryString: url }))
}
render() {
return <input type='text' value={this.state.queryString} style={{ width: '800px' }} />
}
}
class ModelNums extends React.Component<{ state: State }> {
render() {
return <input type='text' defaultValue='1' style={{ width: '300px' }} onChange={t =>
this.props.state.models.next(t.currentTarget.value.split(',')
.map(v => v.trim())
.filter(v => !!v)
.map(v => +v)
)} />
}
}
const state: State = {
query: new Rx.BehaviorSubject(QueryList[1].definition),
id: new Rx.BehaviorSubject('1cbs'),
params: new Rx.BehaviorSubject({ }),
isBinary: new Rx.BehaviorSubject<boolean>(false),
models: new Rx.BehaviorSubject<number[]>([]),
url: new Rx.Subject()
}
function formatParams(def: QueryDefinition) {
const prms = Object.create(null);
for (const p of def.jsonParams) {
prms[p.name] = p.exampleValues ? p.exampleValues[0] : void 0;
}
return JSON.stringify(prms, void 0, 2);
}
function formatUrl() {
const json = JSON.stringify({
name: state.query.value.name,
id: state.id.value,
modelNums: state.models.value.length ? state.models.value : void 0,
binary: state.isBinary.value,
params: state.params.value
});
state.url.next(encodeURIComponent(json));
}
Rx.merge(state.query, state.id, state.params, state.isBinary, state.models).subscribe(s => formatUrl());
ReactDOM.render(<Root state={state} />, document.getElementById('app'));

View File

@@ -1,11 +1,10 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as _ from '../../mol-plugin-state/transforms';
import * as _ from '../../mol-plugin/state/transforms'
import { StateTransformer, StateObject } from '../../mol-state';
import { StringBuilder } from '../../mol-util';
import * as fs from 'fs';
@@ -14,7 +13,7 @@ import { PluginContext } from '../../mol-plugin/context';
import { ParamDefinition } from '../../mol-util/param-definition';
// force the transform to be evaluated
_.StateTransforms.Data.Download.id;
_.StateTransforms.Data.Download.id
// Empty plugin context
const ctx = new PluginContext({
@@ -33,7 +32,7 @@ function writeTransformer(t: StateTransformer) {
StringBuilder.write(builder, `## <a name="${t.id.replace('.', '-')}"></a>${t.id} :: ${typeToString(t.definition.from)} -> ${typeToString(t.definition.to)}`);
StringBuilder.newline(builder);
if (t.definition.display.description) {
StringBuilder.write(builder, `*${t.definition.display.description}*`);
StringBuilder.write(builder, `*${t.definition.display.description}*`)
StringBuilder.newline(builder);
}
StringBuilder.newline(builder);
@@ -49,7 +48,7 @@ function writeTransformer(t: StateTransformer) {
StringBuilder.write(builder, `\`\`\`js\n${JSON.stringify(ParamDefinition.getDefaultValues(params), null, 2)}\n\`\`\``);
StringBuilder.newline(builder);
}
StringBuilder.write(builder, '----------------------------');
StringBuilder.write(builder, '----------------------------')
StringBuilder.newline(builder);
}
@@ -63,7 +62,7 @@ transformers.forEach(t => {
StringBuilder.newline(builder);
});
StringBuilder.newline(builder);
StringBuilder.write(builder, '----------------------------');
StringBuilder.write(builder, '----------------------------')
StringBuilder.newline(builder);
transformers.forEach(t => writeTransformer(t));

View File

@@ -19,15 +19,10 @@ function paramInfo(param: PD.Any, offset: number): string {
case 'conditioned': return getParams(param.conditionParams, offset);
case 'multi-select': return `Array of ${oToS(param.options)}`;
case 'color': return 'Color as 0xrrggbb';
case 'color-list': return `A list of colors as 0xrrggbb`;
case 'color-list': return `One of ${oToS(param.options)}`;
case 'vec3': return `3D vector [x, y, z]`;
case 'mat4': return `4x4 transformation matrix`;
case 'url': return `URL couple with unique identifier`;
case 'file': return `JavaScript File Handle`;
case 'file-list': return `JavaScript FileList Handle`;
case 'select': return `One of ${oToS(param.options)}`;
case 'value-ref': return `Reference to a runtime defined value.`;
case 'data-ref': return `Reference to a computed data value.`;
case 'text': return 'String';
case 'interval': return `Interval [min, max]`;
case 'group': return `Object with:\n${getParams(param.params, offset + 2)}`;
@@ -43,7 +38,7 @@ function paramInfo(param: PD.Any, offset: number): string {
}
}
function oToS(options: readonly (readonly [string, string] | readonly [string, string, string | undefined])[]) {
function oToS(options: [string, string][]) {
return options.map(o => `'${o[0]}'`).join(', ');
}

View File

@@ -4,19 +4,19 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as util from 'util';
import * as fs from 'fs';
import fetch from 'node-fetch';
import * as util from 'util'
import * as fs from 'fs'
import fetch from 'node-fetch'
require('util.promisify').shim();
import { CIF } from '../../mol-io/reader/cif';
import { Progress } from '../../mol-task';
import { CIF } from '../../mol-io/reader/cif'
import { Progress } from '../../mol-task'
const readFileAsync = util.promisify(fs.readFile);
async function readFile(path: string) {
if (path.match(/\.bcif$/)) {
const input = await readFileAsync(path);
const input = await readFileAsync(path)
const data = new Uint8Array(input.byteLength);
for (let i = 0; i < input.byteLength; i++) data[i] = input[i];
return data;

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
@@ -6,20 +5,17 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as argparse from 'argparse';
import * as argparse from 'argparse'
require('util.promisify').shim();
import { CifFrame } from '../../mol-io/reader/cif';
import { Model, Structure, StructureElement, Unit, StructureProperties, UnitRing, Trajectory } from '../../mol-model/structure';
import { CifFrame } from '../../mol-io/reader/cif'
import { Model, Structure, StructureElement, Unit, StructureProperties, UnitRing } from '../../mol-model/structure'
// import { Run, Progress } from '../../mol-task'
import { OrderedSet } from '../../mol-data/int';
import { openCif, downloadCif } from './helpers';
import { Vec3 } from '../../mol-math/linear-algebra';
import { trajectoryFromMmCIF } from '../../mol-model-formats/structure/mmcif';
import { Sequence } from '../../mol-model/sequence';
import { ModelSecondaryStructure } from '../../mol-model-formats/structure/property/secondary-structure';
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
import { Task } from '../../mol-task';
async function downloadFromPdb(pdb: string) {
@@ -34,32 +30,28 @@ export async function readCifFile(path: string) {
}
export function atomLabel(model: Model, aI: number) {
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy;
const { label_atom_id, label_comp_id } = atoms;
const { label_seq_id } = residues;
const { label_asym_id } = chains;
const rI = residueAtomSegments.index[aI];
const cI = chainAtomSegments.index[aI];
return `${label_asym_id.value(cI)} ${label_comp_id.value(aI)} ${label_seq_id.value(rI)} ${label_atom_id.value(aI)}`;
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy
const { label_atom_id } = atoms
const { label_comp_id, label_seq_id } = residues
const { label_asym_id } = chains
const rI = residueAtomSegments.index[aI]
const cI = chainAtomSegments.index[aI]
return `${label_asym_id.value(cI)} ${label_comp_id.value(rI)} ${label_seq_id.value(rI)} ${label_atom_id.value(aI)}`
}
export function residueLabel(model: Model, rI: number) {
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy;
const { label_comp_id } = atoms;
const { label_seq_id } = residues;
const { label_asym_id } = chains;
const aI = residueAtomSegments.offsets[rI];
const cI = chainAtomSegments.index[aI];
return `${label_asym_id.value(cI)} ${label_comp_id.value(aI)} ${label_seq_id.value(rI)}`;
const { residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy
const { label_comp_id, label_seq_id } = residues
const { label_asym_id } = chains
const cI = chainAtomSegments.index[residueAtomSegments.offsets[rI]]
return `${label_asym_id.value(cI)} ${label_comp_id.value(rI)} ${label_seq_id.value(rI)}`
}
export function printSecStructure(model: Model) {
console.log('\nSecondary Structure\n=============');
const { residues } = model.atomicHierarchy;
const secondaryStructure = ModelSecondaryStructure.Provider.get(model);
if (!secondaryStructure) return;
const { key, elements } = model.properties.secondaryStructure;
const { key, elements } = secondaryStructure;
const count = residues._rowCount;
let rI = 0;
while (rI < count) {
@@ -73,14 +65,14 @@ export function printSecStructure(model: Model) {
}
}
export function printBonds(structure: Structure, showIntra: boolean, showInter: boolean) {
export function printLinks(structure: Structure, showIntra: boolean, showInter: boolean) {
if (showIntra) {
console.log('\nIntra Unit Bonds\n=============');
console.log('\nIntra Unit Links\n=============');
for (const unit of structure.units) {
if (!Unit.isAtomic(unit)) continue;
const elements = unit.elements;
const { a, b, edgeCount } = unit.bonds;
const { a, b, edgeCount } = unit.links;
const { model } = unit;
if (!edgeCount) continue;
@@ -94,22 +86,20 @@ export function printBonds(structure: Structure, showIntra: boolean, showInter:
}
if (showInter) {
console.log('\nInter Unit Bonds\n=============');
const bonds = structure.interUnitBonds;
console.log('\nInter Unit Links\n=============');
const links = structure.links;
for (const unit of structure.units) {
if (!Unit.isAtomic(unit)) continue;
for (const pairBonds of bonds.getConnectedUnits(unit.id)) {
if (!pairBonds.areUnitsOrdered || pairBonds.edgeCount === 0) continue;
for (const pairLinks of links.getLinkedUnits(unit)) {
if (!pairLinks.areUnitsOrdered || pairLinks.bondCount === 0) continue;
const { unitA, unitB, edgeCount } = pairBonds;
const uA = structure.unitMap.get(unitA);
const uB = structure.unitMap.get(unitB);
console.log(`${unitA} - ${unitB}: ${edgeCount} bond(s)`);
const { unitA, unitB } = pairLinks;
console.log(`${pairLinks.unitA.id} - ${pairLinks.unitB.id}: ${pairLinks.bondCount} bond(s)`);
for (const aI of pairBonds.connectedIndices) {
for (const bond of pairBonds.getEdges(aI)) {
console.log(`${atomLabel(uA.model, uA.elements[aI])} -- ${atomLabel(uB.model, uB.elements[bond.indexB])}`);
for (const aI of pairLinks.linkedElementIndices) {
for (const link of pairLinks.getBonds(aI)) {
console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[link.indexB])}`);
}
}
}
@@ -122,13 +112,25 @@ export function printSequence(model: Model) {
const { byEntityKey } = model.sequence;
for (const key of Object.keys(byEntityKey)) {
const { sequence, entityId } = byEntityKey[+key];
const { seqId, compId } = sequence;
console.log(`${entityId} (${sequence.kind} ${seqId.value(0)}, ${seqId.value(seqId.rowCount - 1)}) (${compId.value(0)}, ${compId.value(compId.rowCount - 1)})`);
const { seqId, compId } = sequence
console.log(`${entityId} (${sequence.kind} ${seqId.value(0)} (offset ${sequence.offset}), ${seqId.value(seqId.rowCount - 1)}) (${compId.value(0)}, ${compId.value(compId.rowCount - 1)})`);
console.log(`${Sequence.getSequenceString(sequence)}`);
}
console.log();
}
export function printModRes(model: Model) {
console.log('\nModified Residues\n=============');
const map = model.properties.modifiedResidues.parentId;
const { label_comp_id, _rowCount } = model.atomicHierarchy.residues;
for (let i = 0; i < _rowCount; i++) {
const comp_id = label_comp_id.value(i);
if (!map.has(comp_id)) continue;
console.log(`[${i}] ${map.get(comp_id)} -> ${comp_id}`);
}
console.log();
}
export function printRings(structure: Structure) {
console.log('\nRings\n=============');
for (const unit of structure.units) {
@@ -138,7 +140,7 @@ export function printRings(structure: Structure) {
for (let i = 0, _i = Math.min(5, all.length); i < _i; i++) {
fps[fps.length] = UnitRing.fingerprint(unit, all[i]);
}
if (all.length > 5) fps.push('...');
if (all.length > 5) fps.push('...')
console.log(`Unit ${unit.id}, ${all.length} ring(s), ${byFingerprint.size} different fingerprint(s).\n ${fps.join(', ')}`);
}
console.log();
@@ -146,7 +148,7 @@ export function printRings(structure: Structure) {
export function printUnits(structure: Structure) {
console.log('\nUnits\n=============');
const l = StructureElement.Location.create(structure);
const l = StructureElement.Location.create();
for (const unit of structure.units) {
l.unit = unit;
@@ -177,8 +179,7 @@ export function printUnits(structure: Structure) {
export function printSymmetryInfo(model: Model) {
console.log('\nSymmetry Info\n=============');
const symmetry = ModelSymmetry.Provider.get(model);
if (!symmetry) return;
const { symmetry } = model;
const { size, anglesInRadians } = symmetry.spacegroup.cell;
console.log(`Spacegroup: ${symmetry.spacegroup.name} size: ${Vec3.toString(size)} angles: ${Vec3.toString(anglesInRadians)}`);
console.log(`Assembly names: ${symmetry.assemblies.map(a => a.id).join(', ')}`);
@@ -186,11 +187,10 @@ export function printSymmetryInfo(model: Model) {
console.log(`NCS operators: ${symmetry.ncsOperators && symmetry.ncsOperators.map(a => a.name).join(', ')}`);
}
export async function printModelStats(models: Trajectory) {
export function printModelStats(models: ReadonlyArray<Model>) {
console.log('\nModels\n=============');
for (let i = 0; i < models.frameCount; i++) {
const m = await Task.resolveInContext(models.getFrameAtIndex(i));
for (const m of models) {
if (m.coarseHierarchy.isDefined) {
console.log(`${m.label} ${m.modelNum}: ${m.atomicHierarchy.atoms._rowCount} atom(s), ${m.coarseHierarchy.spheres.count} sphere(s), ${m.coarseHierarchy.gaussians.count} gaussian(s)`);
} else {
@@ -202,7 +202,7 @@ export async function printModelStats(models: Trajectory) {
export async function getModelsAndStructure(frame: CifFrame) {
const models = await trajectoryFromMmCIF(frame).run();
const structure = Structure.ofModel(models.representative);
const structure = Structure.ofModel(models[0]);
return { models, structure };
}
@@ -210,17 +210,18 @@ async function run(frame: CifFrame, args: Args) {
const { models, structure } = await getModelsAndStructure(frame);
if (args.models) printModelStats(models);
if (args.seq) printSequence(models.representative);
if (args.seq) printSequence(models[0]);
if (args.units) printUnits(structure);
if (args.sym) printSymmetryInfo(models.representative);
if (args.sym) printSymmetryInfo(models[0]);
if (args.rings) printRings(structure);
if (args.intraBonds) printBonds(structure, true, false);
if (args.interBonds) printBonds(structure, false, true);
if (args.sec) printSecStructure(models.representative);
if (args.intraLinks) printLinks(structure, true, false);
if (args.interLinks) printLinks(structure, false, true);
if (args.mod) printModRes(models[0]);
if (args.sec) printSecStructure(models[0]);
}
async function runDL(pdb: string, args: Args) {
const mmcif = await downloadFromPdb(pdb);
const mmcif = await downloadFromPdb(pdb)
run(mmcif, args);
}
@@ -241,8 +242,8 @@ parser.addArgument(['--seq'], { help: 'print sequence', action: 'storeTrue' });
parser.addArgument(['--units'], { help: 'print units', action: 'storeTrue' });
parser.addArgument(['--sym'], { help: 'print symmetry', action: 'storeTrue' });
parser.addArgument(['--rings'], { help: 'print rings', action: 'storeTrue' });
parser.addArgument(['--intraBonds'], { help: 'print intra unit bonds', action: 'storeTrue' });
parser.addArgument(['--interBonds'], { help: 'print inter unit bonds', action: 'storeTrue' });
parser.addArgument(['--intraLinks'], { help: 'print intra unit links', action: 'storeTrue' });
parser.addArgument(['--interLinks'], { help: 'print inter unit links', action: 'storeTrue' });
parser.addArgument(['--mod'], { help: 'print modified residues', action: 'storeTrue' });
parser.addArgument(['--sec'], { help: 'print secoundary structure', action: 'storeTrue' });
interface Args {
@@ -255,12 +256,12 @@ interface Args {
units?: boolean,
sym?: boolean,
rings?: boolean,
intraBonds?: boolean,
interBonds?: boolean,
intraLinks?: boolean,
interLinks?: boolean,
mod?: boolean,
sec?: boolean,
}
const args: Args = parser.parseArgs();
if (args.download) runDL(args.download, args);
else if (args.file) runFile(args.file, args);
if (args.download) runDL(args.download, args)
else if (args.file) runFile(args.file, args)

View File

@@ -1,44 +1,46 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as fs from 'fs';
import * as argparse from 'argparse';
import * as util from 'util';
import * as fs from 'fs'
import * as argparse from 'argparse'
import * as util from 'util'
import { Volume } from '../../mol-model/volume';
import { downloadCif } from './helpers';
import { CIF } from '../../mol-io/reader/cif';
import { VolumeData, VolumeIsoValue } from '../../mol-model/volume'
import { downloadCif } from './helpers'
import { CIF } from '../../mol-io/reader/cif'
import { DensityServer_Data_Database } from '../../mol-io/reader/cif/schema/density-server';
import { Table } from '../../mol-data/db';
import { StringBuilder } from '../../mol-util';
import { Task } from '../../mol-task';
import { createVolumeIsosurfaceMesh } from '../../mol-repr/volume/isosurface';
import { Theme } from '../../mol-theme/theme';
import { volumeFromDensityServerData, DscifFormat } from '../../mol-model-formats/volume/density-server';
import { createEmptyTheme } from '../../mol-theme/theme';
import { volumeFromDensityServerData } from '../../mol-model-formats/volume/density-server';
require('util.promisify').shim();
const writeFileAsync = util.promisify(fs.writeFile);
type Volume = { source: DensityServer_Data_Database, volume: VolumeData }
async function getVolume(url: string): Promise<Volume> {
const cif = await downloadCif(url, true);
const data = CIF.schema.densityServer(cif.blocks[1]);
return await volumeFromDensityServerData(data).run();
return { source: data, volume: await volumeFromDensityServerData(data).run() };
}
function print(volume: Volume) {
if (!DscifFormat.is(volume.sourceData)) return;
const { volume_data_3d_info } = volume.sourceData.data;
function print(data: Volume) {
const { volume_data_3d_info } = data.source;
const row = Table.getRow(volume_data_3d_info, 0);
console.log(row);
console.log(volume.grid.transform);
console.log(volume.grid.stats);
console.log(data.volume.cell);
console.log(data.volume.dataStats);
console.log(data.volume.fractionalBox);
}
async function doMesh(volume: Volume, filename: string) {
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) } )).run();
async function doMesh(data: Volume, filename: string) {
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, data.volume, createEmptyTheme(), { isoValue: VolumeIsoValue.absolute(1.5) } )).run();
console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount });
// Export the mesh in OBJ format.
@@ -75,8 +77,8 @@ async function run(url: string, meshFilename: string) {
}
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Info about VolumeData from mol-model module'
addHelp: true,
description: 'Info about VolumeData from mol-model module'
});
parser.addArgument([ '--emdb', '-e' ], {
help: 'EMDB id, for example 8116',

View File

@@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="icon" href="./favicon.ico" type="image/x-icon">
<title>Embedded Mol* Viewer</title>
<style>
#app {
position: absolute;
left: 100px;
top: 100px;
width: 800px;
height: 600px;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./molstar.js"></script>
<script type="text/javascript">
var viewer = new molstar.Viewer('app', {
layoutIsExpanded: false,
layoutShowControls: false,
layoutShowRemoteState: false,
layoutShowSequence: true,
layoutShowLog: false,
layoutShowLeftPanel: true,
viewportShowExpand: true,
viewportShowSelectionMode: false,
viewportShowAnimation: false,
pdbProvider: 'rcsb',
emdbProvider: 'rcsb',
});
viewer.loadPdb('7bv2');
viewer.loadEmdb('EMD-30210', { detail: 6 });
// viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } })
</script>
</body>
</html>

View File

@@ -0,0 +1,228 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Ludovic Autin <autin@scripps.edu>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Quat, Mat4 } from '../../../../mol-math/linear-algebra';
import { NumberArray } from '../../../../mol-util/type-helpers';
interface Frame {
t: Vec3,
r: Vec3,
s: Vec3,
}
const a0Tmp = Vec3()
const a1Tmp = Vec3()
const a2Tmp = Vec3()
const a3Tmp = Vec3()
function CubicInterpolate(out: Vec3, y0: Vec3, y1: Vec3, y2: Vec3, y3: Vec3, mu: number): Vec3 {
const mu2 = mu * mu;
Vec3.sub(a0Tmp, y3, y2)
Vec3.sub(a0Tmp, a0Tmp, y0)
Vec3.add(a0Tmp, a0Tmp, y1)
Vec3.sub(a1Tmp, y0, y1)
Vec3.sub(a1Tmp, a1Tmp, a0Tmp)
Vec3.sub(a2Tmp, y2, y0)
Vec3.copy(a3Tmp, y1)
out[0] = a0Tmp[0] * mu * mu2 + a1Tmp[0] * mu2 + a2Tmp[0] * mu + a3Tmp[0]
out[1] = a0Tmp[1] * mu * mu2 + a1Tmp[1] * mu2 + a2Tmp[1] * mu + a3Tmp[1]
out[2] = a0Tmp[2] * mu * mu2 + a1Tmp[2] * mu2 + a2Tmp[2] * mu + a3Tmp[2]
return out
}
const cp0 = Vec3()
const cp1 = Vec3()
const cp2 = Vec3()
const cp3 = Vec3()
const currentPosition = Vec3()
function ResampleControlPoints(points: NumberArray, segmentLength: number) {
const nP = points.length / 3
// insert a point at the end and at the begining
// controlPoints.Insert(0, controlPoints[0] + (controlPoints[0] - controlPoints[1]) / 2.0f);
// controlPoints.Add(controlPoints[nP - 1] + (controlPoints[nP - 1] - controlPoints[nP - 2]) / 2.0f);
let resampledControlPoints: Vec3[] = []
// resampledControlPoints.Add(controlPoints[0]);
// resampledControlPoints.Add(controlPoints[1]);
let idx = 1
// const currentPosition = Vec3.create(points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2])
Vec3.fromArray(currentPosition, points, idx * 3)
let lerpValue = 0.0
// Normalize the distance between control points
while (true) {
if (idx + 2 >= nP) break
Vec3.fromArray(cp0, points, (idx - 1) * 3)
Vec3.fromArray(cp1, points, idx * 3)
Vec3.fromArray(cp2, points, (idx + 1) * 3)
Vec3.fromArray(cp3, points, (idx + 2) * 3)
// const cp0 = Vec3.create(points[(idx-1)*3], points[(idx-1)*3+1], points[(idx-1)*3+2]) // controlPoints[currentPointId - 1];
// const cp1 = Vec3.create(points[idx*3], points[idx*3+1], points[idx*3+2]) // controlPoints[currentPointId];
// const cp2 = Vec3.create(points[(idx+1)*3], points[(idx+1)*3+1], points[(idx+1)*3+2]) // controlPoints[currentPointId + 1];
// const cp3 = Vec3.create(points[(idx+2)*3], points[(idx+2)*3+1], points[(idx+2)*3+2]); // controlPoints[currentPointId + 2];
let found = false
for (; lerpValue <= 1; lerpValue += 0.01) {
// lerp?slerp
// let candidate:Vec3 = Vec3.lerp(Vec3.zero(), cp0, cp1, lerpValue);
// const candidate:Vec3 = Vec3.bezier(Vec3.zero(), cp0, cp1, cp2, cp3, lerpValue);
const candidate = CubicInterpolate(Vec3(), cp0, cp1, cp2, cp3, lerpValue)
const d = Vec3.distance(currentPosition, candidate);
if (d > segmentLength) {
resampledControlPoints.push(candidate)
Vec3.copy(currentPosition, candidate)
found = true
break
}
}
if (!found) {
lerpValue = 0
idx += 1
}
}
return resampledControlPoints
}
const prevV = Vec3()
const tmpV1 = Vec3()
const tmpV2 = Vec3()
const tmpV3 = Vec3()
// easier to align to theses normals
function GetSmoothNormals(points: Vec3[]) {
const nP: number = points.length;
const smoothNormals: Vec3[] = []
if (points.length < 3) {
for (let i = 0; i < points.length; ++i)
smoothNormals.push(Vec3.normalize(Vec3(), points[i]))
return smoothNormals;
}
let p0 = points[0]
let p1 = points[1]
let p2 = points[2]
const p21 = Vec3.sub(tmpV1, p2, p1)
const p01 = Vec3.sub(tmpV2, p0, p1)
const p0121 = Vec3.cross(tmpV3, p01, p21)
Vec3.normalize(prevV, p0121)
smoothNormals.push(Vec3.clone(prevV))
for (let i = 1; i < points.length - 1; ++i) {
p0 = points[i - 1]
p1 = points[i]
p2 = points[i + 1]
const t = Vec3.normalize(tmpV1, Vec3.sub(tmpV1, p2 , p0))
const b = Vec3.normalize(tmpV2, Vec3.cross(tmpV2, t, prevV))
const n = Vec3.normalize(Vec3(), Vec3.cross(tmpV3, t, b))
Vec3.negate(n, n)
Vec3.copy(prevV, n)
smoothNormals.push(n)
}
const last = Vec3()
Vec3.normalize(last, Vec3.cross(last,
Vec3.sub(tmpV1, points[nP - 3], points[nP-2]),
Vec3.sub(tmpV2, points[nP-2] , points[nP-1]))
)
smoothNormals.push(last)
return smoothNormals;
}
const frameTmpV1 = Vec3()
const frameTmpV2 = Vec3()
const frameTmpV3 = Vec3()
function getFrame(reference: Vec3, tangent: Vec3) {
const t = Vec3.normalize(Vec3(), tangent);
// make reference vector orthogonal to tangent
const proj_r_to_t = Vec3.scale(
frameTmpV1, tangent, Vec3.dot(reference, tangent) / Vec3.dot(tangent, tangent)
)
const r = Vec3.normalize(Vec3(), Vec3.sub(frameTmpV2, reference, proj_r_to_t))
// make bitangent vector orthogonal to the others
const s = Vec3.normalize(Vec3(), Vec3.cross(frameTmpV3, t, r))
return { t, r, s }
}
const mfTmpV1 = Vec3()
const mfTmpV2 = Vec3()
const mfTmpV3 = Vec3()
const mfTmpV4 = Vec3()
const mfTmpV5 = Vec3()
const mfTmpV6 = Vec3()
const mfTmpV7 = Vec3()
const mfTmpV8 = Vec3()
const mfTmpV9 = Vec3()
// easier to align to theses normals
// https://github.com/bzamecnik/gpg/blob/master/rotation-minimizing-frame/rmf.py
function GetMiniFrame(points: Vec3[], normals: Vec3[]) {
const frames: Frame[] = [];
const t0 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[1], points[0]))
frames.push(getFrame(normals[0], t0))
for (let i = 0; i< points.length-2; ++i) {
const t2 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[i+2], points[i+1]))
const v1 = Vec3.sub(mfTmpV2, points[i + 1], points[i]) // this is tangeant
const c1 = Vec3.dot(v1, v1)
// compute r_i^L = R_1 * r_i
const v1r = Vec3.scale(mfTmpV3, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].r))
const ref_L_i = Vec3.sub(mfTmpV4, frames[i].r, v1r)
// compute t_i^L = R_1 * t_i
const v1t = Vec3.scale(mfTmpV5, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].t))
const tan_L_i = Vec3.sub(mfTmpV6, frames[i].t, v1t)
// # compute reflection vector of R_2
const v2 = Vec3.sub(mfTmpV7, t2 , tan_L_i)
const c2 = Vec3.dot(v2, v2)
// compute r_(i+1) = R_2 * r_i^L
const v2l = Vec3.scale(mfTmpV8, v1, (2.0/c2) * Vec3.dot(v2, ref_L_i))
const ref_next = Vec3.sub(mfTmpV9, ref_L_i, v2l) // ref_L_i - (2 / c2) * v2.dot(ref_L_i) * v2
frames.push(getFrame(ref_next, t2)) // frames.append(Frame(ref_next, tangents[i+1]))
}
return frames;
}
const rpTmpVec1 = Vec3()
export function getMatFromResamplePoints(points: NumberArray) {
const segmentLength = 3.4
const new_points = ResampleControlPoints(points, 3.4)
const npoints = new_points.length
const new_normal = GetSmoothNormals(new_points)
const frames = GetMiniFrame(new_points, new_normal)
const limit = npoints
const transforms: Mat4[] = []
const pti = Vec3.copy(rpTmpVec1, new_points[0]);
// console.log(new_points.length)
// console.log(points.length/3)
// console.log(limit)
// console.log(segmentLength)
for (let i = 0; i<npoints-2; ++i) {
const pti1: Vec3 = new_points[i+1] // Vec3.create(points[(i+1)*3],points[(i+1)*3+1],points[(i+1)*3+2]);
const d = Vec3.distance(pti, pti1)
if (d >= segmentLength) {
// use twist or random?
const quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t) // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal
const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random()*3.60 ) // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();//
const m = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)) // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat));
// let pos:Vec3 = Vec3.add(Vec3.zero(),pti1,pti)
// pos = Vec3.scale(pos,pos,1.0/2.0);
// Vec3.makeRotation(Mat4.zero(),Vec3.create(0,0,1),frames[i].t);//
Mat4.setTranslation(m, pti1)
// let m2:Mat4 = GetTubePropertiesMatrix(pti,pti1);
// let q:Quat = Quat.rotationTo(Quat.zero(), Vec3.create(0,1,0),Vec3.create(0,0,1))
// m2=Mat4.mul(Mat4.identity(),Mat4.fromQuat(Mat4.zero(),q),m2);
transforms.push(m)
Vec3.copy(pti, pti1)
}
if (transforms.length >= limit) break
}
return transforms
}

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Quat } from '../../../../mol-math/linear-algebra';
export interface CellPack {
cell: Cell
packings: CellPacking[]
}
export interface CellPacking {
name: string,
location: 'surface' | 'interior' | 'cytoplasme',
ingredients: Packing['ingredients']
}
//
export interface Cell {
recipe: Recipe
cytoplasme?: Packing
compartments?: { [key: string]: Compartment }
}
export interface Recipe {
setupfile: string
/** First entry is name, secound is path: [name: string, path: string][] */
paths: [string, string][]
version: string
name: string
}
export interface Compartment {
surface?: Packing
interior?: Packing
}
export interface Packing {
ingredients: { [key: string]: Ingredient }
}
export interface Ingredient {
source: IngredientSource
results: [Vec3, Quat][]
name: string
positions?: [Vec3[]] // why wrapped in an extra array?
radii?: [number[]] // why wrapped in an extra array?
/** Number of `curveX` properties in the object where `X` is a 0-indexed number */
nbCurve?: number
/** Curve properties are Vec3[] but that is not expressable in TypeScript */
[curveX: string]: unknown
}
export interface IngredientSource {
pdb: string
transform: { center: boolean, translate?: Vec3 }
biomt?: boolean
}

View File

@@ -0,0 +1,474 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { StateAction } from '../../../../mol-state';
import { PluginContext } from '../../../../mol-plugin/context';
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, 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';
import { SymmetryOperator } from '../../../../mol-math/geometry';
import { Task } from '../../../../mol-task';
import { StructureRepresentation3DHelpers } from '../../../../mol-plugin/state/transforms/representation';
import { StateTransforms } from '../../../../mol-plugin/state/transforms';
import { distinctColors } from '../../../../mol-util/color/distinct';
import { ModelIndexColorThemeProvider } from '../../../../mol-theme/color/model-index';
import { Hcl } from '../../../../mol-util/color/spaces/hcl';
import { ParseCellPack, StructureFromCellpack, DefaultCellPackBaseUrl } from './state';
import { MolScriptBuilder as MS } from '../../../../mol-script/language/builder';
import { getMatFromResamplePoints } from './curve';
import { compile } from '../../../../mol-script/runtime/query/compiler';
import { UniformColorThemeProvider } from '../../../../mol-theme/color/uniform';
import { ThemeRegistryContext } from '../../../../mol-theme/theme';
import { ColorTheme } from '../../../../mol-theme/color';
import { _parse_mmCif } from '../../../../mol-model-formats/structure/mmcif/parser';
import { ModelFormat } from '../../../../mol-model-formats/structure/format';
import { CifCategory, CifField } from '../../../../mol-io/reader/cif';
import { mmCIF_Schema } from '../../../../mol-io/reader/cif/schema/mmcif';
import { Column } from '../../../../mol-data/db';
function getCellPackModelUrl(fileName: string, baseUrl: string) {
return `${baseUrl}/results/${fileName}`
}
async function getModel(id: string, baseUrl: string) {
let model: Model;
if (id.match(/^[1-9][a-zA-Z0-9]{3,3}$/i)) {
// return
const cif = await getFromPdb(id)
model = (await trajectoryFromMmCIF(cif).run())[0]
} else {
const pdb = await getFromCellPackDB(id, baseUrl)
model = (await trajectoryFromPDB(pdb).run())[0]
}
return model
}
async function getStructure(model: Model, props: { assembly?: string } = {}) {
let structure = Structure.ofModel(model)
const { assembly } = props
if (assembly) {
structure = await StructureSymmetry.buildAssembly(structure, assembly).run()
}
const query = MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer'])
})
])
const compiled = compile<StructureSelection>(query)
const result = compiled(new QueryContext(structure))
structure = StructureSelection.unionStructure(result)
return structure
}
function getTransform(trans: Vec3, rot: Quat) {
const q: Quat = Quat.create(-rot[3], rot[0], rot[1], rot[2])
const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q)
Mat4.transpose(m, m)
Mat4.scale(m, m, Vec3.create(-1.0, 1.0, -1.0))
Mat4.setTranslation(m, trans)
return m
}
function getResultTransforms(results: Ingredient['results']) {
return results.map((r: Ingredient['results'][0]) => getTransform(r[0], r[1]))
}
function getCurveTransforms(ingredient: Ingredient) {
const n = ingredient.nbCurve || 0
const instances: Mat4[] = []
for (let i = 0; i < n; ++i) {
const cname = `curve${i}`
if (!(cname in ingredient)) {
// console.warn(`Expected '${cname}' in ingredient`)
continue
}
const _points = ingredient[cname] as Vec3[]
if (_points.length <= 2) {
// TODO handle curve with 2 or less points
continue
}
const points = new Float32Array(_points.length * 3)
for (let i = 0, il = _points.length; i < il; ++i) Vec3.toArray(_points[i], points, i * 3)
const newInstances = getMatFromResamplePoints(points)
instances.push(...newInstances)
}
return instances
}
function getAssembly(transforms: Mat4[], structure: Structure) {
const builder = Structure.Builder()
const { units } = structure;
for (let i = 0, il = transforms.length; i < il; ++i) {
const id = `${i + 1}`
const op = SymmetryOperator.create(id, transforms[i], { id, operList: [ id ] })
for (const unit of units) {
builder.addWithOperator(unit, op)
}
}
return builder.getStructure();
}
function getCifCurve(name: string, transforms: Mat4[], model: Model) {
const d = model.sourceData.data.atom_site
const n = d._rowCount
const rowCount = n * transforms.length
const { offsets, count } = model.atomicHierarchy.chainAtomSegments
const x = d.Cartn_x.toArray()
const y = d.Cartn_y.toArray()
const z = d.Cartn_z.toArray()
const Cartn_x = new Float32Array(rowCount)
const Cartn_y = new Float32Array(rowCount)
const Cartn_z = new Float32Array(rowCount)
const map = new Uint32Array(rowCount)
const seq = new Int32Array(rowCount)
let offset = 0
for (let c = 0; c < count; ++c) {
const cStart = offsets[c]
const cEnd = offsets[c + 1]
const cLength = cEnd - cStart
for (let t = 0, tl = transforms.length; t < tl; ++t) {
const m = transforms[t]
for (let j = cStart; j < cEnd; ++j) {
const i = offset + j - cStart
const xj = x[j], yj = y[j], zj = z[j]
Cartn_x[i] = m[0] * xj + m[4] * yj + m[8] * zj + m[12]
Cartn_y[i] = m[1] * xj + m[5] * yj + m[9] * zj + m[13]
Cartn_z[i] = m[2] * xj + m[6] * yj + m[10] * zj + m[14]
map[i] = j
seq[i] = t + 1
}
offset += cLength
}
}
function multColumn<T>(column: Column<T>) {
const array = column.toArray()
return Column.ofLambda({
value: row => array[map[row]],
areValuesEqual: (rowA, rowB) => map[rowA] === map[rowB] || array[map[rowA]] === array[map[rowB]],
rowCount, schema: column.schema
})
}
const _atom_site: CifCategory.SomeFields<mmCIF_Schema['atom_site']> = {
auth_asym_id: CifField.ofColumn(multColumn(d.auth_asym_id)),
auth_atom_id: CifField.ofColumn(multColumn(d.auth_atom_id)),
auth_comp_id: CifField.ofColumn(multColumn(d.auth_comp_id)),
auth_seq_id: CifField.ofNumbers(seq),
B_iso_or_equiv: CifField.ofColumn(Column.ofConst(0, rowCount, Column.Schema.float)),
Cartn_x: CifField.ofNumbers(Cartn_x),
Cartn_y: CifField.ofNumbers(Cartn_y),
Cartn_z: CifField.ofNumbers(Cartn_z),
group_PDB: CifField.ofColumn(Column.ofConst('ATOM', rowCount, Column.Schema.str)),
id: CifField.ofColumn(Column.ofLambda({
value: row => row,
areValuesEqual: (rowA, rowB) => rowA === rowB,
rowCount, schema: d.id.schema,
})),
label_alt_id: CifField.ofColumn(multColumn(d.label_alt_id)),
label_asym_id: CifField.ofColumn(multColumn(d.label_asym_id)),
label_atom_id: CifField.ofColumn(multColumn(d.label_atom_id)),
label_comp_id: CifField.ofColumn(multColumn(d.label_comp_id)),
label_seq_id: CifField.ofNumbers(seq),
label_entity_id: CifField.ofColumn(Column.ofConst('1', rowCount, Column.Schema.str)),
occupancy: CifField.ofColumn(Column.ofConst(1, rowCount, Column.Schema.float)),
type_symbol: CifField.ofColumn(multColumn(d.type_symbol)),
pdbx_PDB_ins_code: CifField.ofColumn(Column.ofConst('', rowCount, Column.Schema.str)),
pdbx_PDB_model_num: CifField.ofColumn(Column.ofConst(1, rowCount, Column.Schema.int)),
}
const categories = {
entity: CifCategory.ofTable('entity', model.sourceData.data.entity),
chem_comp: CifCategory.ofTable('chem_comp', model.sourceData.data.chem_comp),
atom_site: CifCategory.ofFields('atom_site', _atom_site)
}
return {
header: name,
categoryNames: Object.keys(categories),
categories
};
}
async function getCurve(name: string, transforms: Mat4[], model: Model) {
const cif = getCifCurve(name, transforms, model)
const curveModelTask = Task.create('Curve Model', async ctx => {
const format = ModelFormat.mmCIF(cif)
const models = await _parse_mmCif(format, ctx)
return models[0]
})
const curveModel = await curveModelTask.run()
return getStructure(curveModel)
}
async function getIngredientStructure(ingredient: Ingredient, baseUrl: string) {
const { name, source, results, nbCurve } = ingredient
// TODO can these be added to the library?
if (name === 'HIV1_CAhex_0_1_0') return
if (name === 'HIV1_CAhexCyclophilA_0_1_0') return
if (name === 'iLDL') return
if (name === 'peptides') return
if (name === 'lypoglycane') return
if (source.pdb === 'None') return
const model = await getModel(source.pdb || name, baseUrl)
if (!model) return
if (nbCurve) {
return getCurve(name, getCurveTransforms(ingredient), model)
} else {
const structure = await getStructure(model, { assembly: source.biomt ? '1' : undefined })
return getAssembly(getResultTransforms(results), structure)
}
}
export function createStructureFromCellPack(packing: CellPacking, baseUrl: string) {
return Task.create('Create Packing Structure', async ctx => {
const { ingredients, name } = packing
const structures: Structure[] = []
for (const iName in ingredients) {
if (ctx.shouldUpdate) await ctx.update(iName)
const s = await getIngredientStructure(ingredients[iName], baseUrl)
if (s) structures.push(s)
}
if (ctx.shouldUpdate) await ctx.update(`${name} - units`)
const builder = Structure.Builder({ label: name })
let offsetInvariantId = 0
for (const s of structures) {
if (ctx.shouldUpdate) await ctx.update(`${s.label}`)
let maxInvariantId = 0
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, Unit.Trait.None, invariantId)
}
offsetInvariantId += maxInvariantId
}
if (ctx.shouldUpdate) await ctx.update(`${name} - structure`)
const s = builder.getStructure()
return s
})
}
export const LoadCellPackModel = StateAction.build({
display: { name: 'Load CellPack Model' },
params: {
id: PD.Select('influenza_model1.json', [
['blood_hiv_immature_inside.json', 'blood_hiv_immature_inside'],
['BloodHIV1.0_mixed_fixed_nc1.cpr', 'BloodHIV1.0_mixed_fixed_nc1'],
['HIV-1_0.1.6-8_mixed_radii_pdb.cpr', 'HIV-1_0.1.6-8_mixed_radii_pdb'],
['influenza_model1.json', 'influenza_model1'],
['Mycoplasma1.5_mixed_pdb_fixed.cpr', 'Mycoplasma1.5_mixed_pdb_fixed'],
['curveTest', 'Curve Test'],
]),
baseUrl: PD.Text(DefaultCellPackBaseUrl),
preset: PD.Group({
traceOnly: PD.Boolean(false),
representation: PD.Select('spacefill', [
['spacefill', 'Spacefill'],
['gaussian-surface', 'Gaussian Surface'],
['point', 'Point'],
] as ['spacefill' | 'gaussian-surface' | 'point', string][])
}, { isExpanded: true })
},
from: PSO.Root
})(({ state, params }, ctx: PluginContext) => Task.create('CellPack Loader', async taskCtx => {
const url = getCellPackModelUrl(params.id, params.baseUrl)
const root = state.build().toRoot();
let cellPackBuilder: any
if (params.id === 'curveTest') {
const url = `${params.baseUrl}/extras/rna_allpoints.json`
const data = await ctx.fetch({ url, type: 'string' }).runInContext(taskCtx);
const { points } = await (new Response(data)).json() as { points: number[] }
const curve0: Vec3[] = []
for (let j = 0, jl = Math.min(points.length, 3 * 100); j < jl; j += 3) {
curve0.push(Vec3.fromArray(Vec3(), points, j))
}
const cell: Cell = {
recipe: { setupfile: '', paths: [], version: '', name: 'Curve Test' },
compartments: {
'CurveCompartment': {
interior: {
ingredients: {
'CurveIngredient': {
source: { pdb: 'RNA_U_Base.pdb', transform: { center: false } },
results: [],
name: 'RNA',
nbCurve: 1,
curve0
}
}
}
}
}
}
cellPackBuilder = root
.apply(StateTransforms.Data.ImportJson, { data: cell }, { state: { isGhost: true } })
.apply(ParseCellPack)
} else {
cellPackBuilder = root
.apply(StateTransforms.Data.Download, { url, isBinary: false, label: params.id }, { state: { isGhost: true } })
.apply(StateTransforms.Data.ParseJson, undefined, { state: { isGhost: true } })
.apply(ParseCellPack)
}
const cellPackObject = await state.updateTree(cellPackBuilder).runInContext(taskCtx)
const { packings } = cellPackObject.data
const tree = state.build().to(cellPackBuilder.ref);
const isHiv = (
params.id === 'BloodHIV1.0_mixed_fixed_nc1.cpr' ||
params.id === 'HIV-1_0.1.6-8_mixed_radii_pdb.cpr'
)
if (isHiv) {
for (let i = 0, il = packings.length; i < il; ++i) {
if (packings[i].name === 'HIV1_capsid_3j3q_PackInner_0_1_0') {
const url = `${params.baseUrl}/extras/rna_allpoints.json`
const data = await ctx.fetch({ url, type: 'string' }).runInContext(taskCtx);
const { points } = await (new Response(data)).json() as { points: number[] }
const curve0: Vec3[] = []
for (let j = 0, jl = points.length; j < jl; j += 3) {
curve0.push(Vec3.fromArray(Vec3(), points, j))
}
packings[i].ingredients['RNA'] = {
source: { pdb: 'RNA_U_Base.pdb', transform: { center: false } },
results: [],
name: 'RNA',
nbCurve: 1,
curve0
}
}
}
}
const colors = distinctColors(packings.length)
for (let i = 0, il = packings.length; i < il; ++i) {
const hcl = Hcl.fromColor(Hcl(), colors[i])
const hue = [Math.max(0, hcl[0] - 35), Math.min(360, hcl[0] + 35)] as [number, number]
const p = { packing: i, baseUrl: params.baseUrl }
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'])
])
})
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),
color: getColorParams(hue)
})
)
}
if (isHiv) {
const url = `${params.baseUrl}/membranes/hiv_lipids.bcif`
tree.apply(StateTransforms.Data.Download, { label: 'hiv_lipids', url, isBinary: true }, { state: { isGhost: true } })
.apply(StateTransforms.Data.ParseCif, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Model.TrajectoryFromMmCif, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Model.ModelFromTrajectory, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Model.StructureFromModel, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Misc.CreateGroup, { label: 'HIV1_envelope_Membrane' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.createParams(ctx, Structure.Empty, {
repr: getReprParams(ctx, params.preset),
color: UniformColorThemeProvider
})
)
}
console.time('cellpack')
await state.updateTree(tree).runInContext(taskCtx);
console.timeEnd('cellpack')
}));
function getReprParams(ctx: PluginContext, params: { representation: 'spacefill' | 'gaussian-surface' | 'point', traceOnly: boolean }) {
const { representation, traceOnly } = params
switch (representation) {
case 'spacefill':
return traceOnly
? [
ctx.structureRepresentation.registry.get('spacefill'),
() => ({ sizeFactor: 2, ignoreHydrogens: true })
] as [any, any]
: [
ctx.structureRepresentation.registry.get('spacefill'),
() => ({ ignoreHydrogens: true })
] as [any, any]
case 'gaussian-surface':
return [
ctx.structureRepresentation.registry.get('gaussian-surface'),
() => ({
quality: 'custom', resolution: 10, radiusOffset: 2,
alpha: 1.0, flatShaded: false, doubleSided: false,
ignoreHydrogens: true
})
] as [any, any]
case 'point':
return [
ctx.structureRepresentation.registry.get('point'),
() => ({ ignoreHydrogens: true })
] as [any, any]
}
}
function getColorParams(hue: [number, number]) {
return [
ModelIndexColorThemeProvider,
(c: ColorTheme.Provider<any>, ctx: ThemeRegistryContext) => {
return {
palette: {
name: 'generate',
params: {
hue, chroma: [30, 80], luminance: [15, 85],
clusteringStepCount: 50, minSampleCount: 800,
maxCount: 75
}
}
}
}
] as [any, any]
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { PluginStateObject as PSO, PluginStateTransform } from '../../../../mol-plugin/state/objects';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { Task } from '../../../../mol-task';
import { CellPack as _CellPack, Cell, CellPacking } from './data';
import { createStructureFromCellPack } from './model';
// export const DefaultCellPackBaseUrl = 'https://cdn.jsdelivr.net/gh/mesoscope/cellPACK_data@master/cellPACK_database_1.1.0/'
export const DefaultCellPackBaseUrl = 'https://mgldev.scripps.edu/projects/autoPACK/web/cellpackproject/'
export class CellPack extends PSO.Create<_CellPack>({ name: 'CellPack', typeClass: 'Object' }) { }
export { ParseCellPack }
type ParseCellPack = typeof ParseCellPack
const ParseCellPack = PluginStateTransform.BuiltIn({
name: 'parse-cellpack',
display: { name: 'Parse CellPack', description: 'Parse CellPack from JSON data' },
from: PSO.Format.Json,
to: CellPack
})({
apply({ a }) {
return Task.create('Parse CellPack', async ctx => {
const cell = a.data as Cell
const packings: CellPacking[] = []
const { compartments, cytoplasme } = cell
if (compartments) {
for (const name in compartments) {
const { surface, interior } = compartments[name]
if (surface) packings.push({ name, location: 'surface', ingredients: surface.ingredients })
if (interior) packings.push({ name, location: 'interior', ingredients: interior.ingredients })
}
}
if (cytoplasme) packings.push({ name: 'Cytoplasme', location: 'cytoplasme', ingredients: cytoplasme.ingredients })
return new CellPack({ cell, packings });
});
}
});
export { StructureFromCellpack }
type StructureFromCellpack = typeof ParseCellPack
const StructureFromCellpack = PluginStateTransform.BuiltIn({
name: 'structure-from-cellpack',
display: { name: 'Structure from CellPack', description: 'Create Structure from CellPack Packing' },
from: CellPack,
to: PSO.Molecule.Structure,
params: a => {
if (!a) {
return {
packing: PD.Numeric(0, {}, { description: 'Packing Index' }),
baseUrl: PD.Text(DefaultCellPackBaseUrl)
};
}
const options = a.data.packings.map((d, i) => [i, d.name] as [number, string])
return {
packing: PD.Select(0, options),
baseUrl: PD.Text(DefaultCellPackBaseUrl)
}
}
})({
apply({ a, params }) {
return Task.create('Structure from CellPack', async ctx => {
const packing = a.data.packings[params.packing]
const structure = await createStructureFromCellPack(packing, params.baseUrl).runInContext(ctx)
return new PSO.Molecule.Structure(structure, { label: packing.name })
});
}
});

View File

@@ -0,0 +1,48 @@
/**
* 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'
import { parsePDB } from '../../../../mol-io/reader/pdb/parser';
async function parseCif(data: string|Uint8Array) {
const comp = CIF.parse(data);
const parsed = await comp.run();
if (parsed.isError) throw parsed;
return parsed.result;
}
async function parsePDBfile(data: string, id: string) {
const comp = parsePDB(data, id);
const parsed = await comp.run();
if (parsed.isError) throw parsed;
return parsed.result;
}
async function downloadCif(url: string, isBinary: boolean) {
const data = await fetch(url);
return parseCif(isBinary ? new Uint8Array(await data.arrayBuffer()) : await data.text());
}
async function downloadPDB(url: string, id: string) {
const data = await fetch(url);
return parsePDBfile(await data.text(), id);
}
export async function getFromPdb(id: string) {
const parsed = await downloadCif(`https://files.rcsb.org/download/${id}.cif`, false);
return parsed.blocks[0];
}
function getCellPackDataUrl(id: string, baseUrl: string) {
const url = `${baseUrl}/other/${id}`
return url.endsWith('.pdb') ? url : `${url}.pdb`
}
export async function getFromCellPackDB(id: string, baseUrl: string) {
const name = id.endsWith('.pdb') ? id.substring(0, id.length - 4) : id
const parsed = await downloadPDB(getCellPackDataUrl(id, baseUrl), name);
return parsed;
}

View File

@@ -0,0 +1,167 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { StateTree, StateBuilder, StateAction, State } from '../../../mol-state';
import { StateTransforms } from '../../../mol-plugin/state/transforms';
import { createModelTree, complexRepresentation } from '../../../mol-plugin/state/actions/structure';
import { PluginContext } from '../../../mol-plugin/context';
import { PluginStateObject } from '../../../mol-plugin/state/objects';
import { ParamDefinition } from '../../../mol-util/param-definition';
import { PluginCommands } from '../../../mol-plugin/command';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { PluginStateSnapshotManager } from '../../../mol-plugin/state/snapshots';
import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
import { Text } from '../../../mol-geo/geometry/text/text';
import { UUID } from '../../../mol-util';
import { ColorNames } from '../../../mol-util/color/names';
import { Camera } from '../../../mol-canvas3d/camera';
import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/transforms/representation';
export const CreateJoleculeState = StateAction.build({
display: { name: 'Jolecule State Import' },
params: { id: ParamDefinition.Text('1mbo') },
from: PluginStateObject.Root
})(async ({ ref, state, params }, plugin: PluginContext) => {
try {
const id = params.id.trim().toLowerCase();
const data = await plugin.runTask(plugin.fetch({ url: `https://jolecule.appspot.com/pdb/${id}.views.json`, type: 'json' })) as JoleculeSnapshot[];
data.sort((a, b) => a.order - b.order);
await PluginCommands.State.RemoveObject.dispatch(plugin, { state, ref });
plugin.state.snapshots.clear();
const template = createTemplate(plugin, state, id);
const snapshots = data.map((e, idx) => buildSnapshot(plugin, template, { e, idx, len: data.length }));
for (const s of snapshots) {
plugin.state.snapshots.add(s);
}
PluginCommands.State.Snapshots.Apply.dispatch(plugin, { id: snapshots[0].snapshot.id });
} catch (e) {
plugin.log.error(`Jolecule Failed: ${e}`);
}
});
interface JoleculeSnapshot {
order: number,
distances: { i_atom1: number, i_atom2: number }[],
labels: { i_atom: number, text: string }[],
camera: { up: Vec3, pos: Vec3, in: Vec3, slab: { z_front: number, z_back: number, zoom: number } },
selected: number[],
text: string
}
function createTemplate(plugin: PluginContext, state: State, id: string) {
const b = new StateBuilder.Root(state.tree);
const data = b.toRoot().apply(StateTransforms.Data.Download, { url: `https://www.ebi.ac.uk/pdbe/static/entry/${id}_updated.cif` }, { state: { isGhost: true }});
const model = createModelTree(data, 'cif');
const structure = model.apply(StateTransforms.Model.StructureFromModel, {});
complexRepresentation(plugin, structure, { hideWater: true });
return { tree: b.getTree(), structure: structure.ref };
}
const labelOptions: ParamDefinition.Values<Text.Params> = {
...ParamDefinition.getDefaultValues(Text.Params),
tether: true,
sizeFactor: 1.3,
attachment: 'bottom-right',
offsetZ: 10,
background: true,
backgroundMargin: 0.2,
backgroundColor: ColorNames.skyblue,
backgroundOpacity: 0.9
}
// const distanceLabelOptions = {
// ...ParamDefinition.getDefaultValues(Text.Params),
// sizeFactor: 1,
// offsetX: 0,
// offsetY: 0,
// offsetZ: 10,
// background: true,
// backgroundMargin: 0.2,
// backgroundColor: ColorNames.snow,
// backgroundOpacity: 0.9
// }
function buildSnapshot(plugin: PluginContext, template: { tree: StateTree, structure: string }, params: { e: JoleculeSnapshot, idx: number, len: number }): PluginStateSnapshotManager.Entry {
const b = new StateBuilder.Root(template.tree);
let i = 0;
for (const l of params.e.labels) {
const expression = createExpression([l.i_atom]);
const group = b.to(template.structure)
.group(StateTransforms.Misc.CreateGroup, { label: `Label ${++i}` });
group
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: 'Atom' })
.apply(StateTransforms.Representation.StructureLabels3D, {
target: { name: 'static-text', params: { value: l.text || '' } },
options: labelOptions
});
group
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: MS.struct.modifier.wholeResidues([ expression ]), label: 'Residue' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick', { }));
}
if (params.e.selected && params.e.selected.length > 0) {
b.to(template.structure)
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: createExpression(params.e.selected), label: `Selected` })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick'));
}
// TODO
// for (const l of params.e.distances) {
// b.to('structure')
// .apply(StateTransforms.Model.StructureSelectionFromExpression, { query: createQuery([l.i_atom1, l.i_atom2]), label: `Distance ${++i}` })
// .apply(StateTransforms.Representation.StructureLabels3D, {
// target: { name: 'static-text', params: { value: l. || '' } },
// options: labelOptions
// });
// }
return PluginStateSnapshotManager.Entry({
id: UUID.create22(),
data: { tree: StateTree.toJSON(b.getTree()) },
camera: {
current: getCameraSnapshot(params.e.camera),
transitionStyle: 'animate',
transitionDurationInMs: 350
}
}, {
name: params.e.text
});
}
function getCameraSnapshot(e: JoleculeSnapshot['camera']): Camera.Snapshot {
const direction = Vec3.sub(Vec3(), e.pos, e.in);
Vec3.normalize(direction, direction);
const up = Vec3.sub(Vec3(), e.pos, e.up);
Vec3.normalize(up, up);
const s: Camera.Snapshot = {
mode: 'perspective',
fov: Math.PI / 4,
position: Vec3.scaleAndAdd(Vec3(), e.pos, direction, e.slab.zoom),
target: e.pos,
radius: (e.slab.z_back - e.slab.z_front) / 2,
fog: 50,
up,
};
return s;
}
function createExpression(atomIndices: number[]) {
if (atomIndices.length === 0) return MS.struct.generator.empty();
return MS.struct.generator.atomGroups({
'atom-test': atomIndices.length === 1
? MS.core.rel.eq([MS.struct.atomProperty.core.sourceIndex(), atomIndices[0]])
: MS.core.set.has([MS.set.apply(null, atomIndices), MS.struct.atomProperty.core.sourceIndex()]),
'group-by': 0
});
}

View File

@@ -34,56 +34,10 @@
height: 600px;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
<link rel="stylesheet" type="text/css" href="app.css" />
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./molstar.js"></script>
<script type="text/javascript">
function getParam(name, regex) {
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
}
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
if (debugMode) molstar.setDebugMode(debugMode, debugMode);
var disableAntialiasing = getParam('disable-antialiasing', '[^&]+').trim() === '1';
var pixelScale = parseFloat(getParam('pixel-scale', '[^&]+').trim() || '1');
var disableWboit = getParam('disable-wboit', '[^&]+').trim() === '1';
var hideControls = getParam('hide-controls', '[^&]+').trim() === '1';
var pdbProvider = getParam('pdb-provider', '[^&]+').trim().toLowerCase();
var emdbProvider = getParam('emdb-provider', '[^&]+').trim().toLowerCase();
var viewer = new molstar.Viewer('app', {
disableAntialiasing: disableAntialiasing,
pixelScale: pixelScale,
enableWboit: !disableWboit,
layoutShowControls: !hideControls,
viewportShowExpand: false,
pdbProvider: pdbProvider || 'pdbe',
emdbProvider: emdbProvider || 'pdbe',
});
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
var snapshotUrl = getParam('snapshot-url', '[^&]+').trim();
var snapshotUrlType = getParam('snapshot-url-type', '[^&]+').toLowerCase().trim() || 'molj';
if (snapshotUrl && snapshotUrlType) viewer.loadSnapshotFromUrl(snapshotUrl, snapshotUrlType);
var structureUrl = getParam('structure-url', '[^&]+').trim();
var structureUrlFormat = getParam('structure-url-format', '[a-z]+').toLowerCase().trim();
var structureUrlIsBinary = getParam('structure-url-is-binary', '[^&]+').trim() === '1';
if (structureUrl) viewer.loadStructureFromUrl(structureUrl, structureUrlFormat, structureUrlIsBinary);
var pdb = getParam('pdb', '[^&]+').trim();
if (pdb) viewer.loadPdb(pdb);
var pdbDev = getParam('pdb-dev', '[^&]+').trim();
if (pdbDev) viewer.loadPdbDev(pdbDev);
var emdb = getParam('emdb', '[^&]+').trim();
if (emdb) viewer.loadEmdb(emdb);
</script>
<script type="text/javascript" src="./index.js"></script>
</body>
</html>

View File

@@ -1,279 +1,67 @@
/**
* Copyright (c) 2018-2020 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>
*/
import '../../mol-util/polyfill';
import { createPlugin } from '../../mol-plugin';
import { DefaultPluginSpec } from '../../mol-plugin/spec';
import './index.html';
import './embedded.html';
import './favicon.ico';
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
import './index.html'
import './favicon.ico'
import { PluginContext } from '../../mol-plugin/context';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginCommands } from '../../mol-plugin/command';
import { PluginSpec } from '../../mol-plugin/spec';
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
import { PluginConfig } from '../../mol-plugin/config';
import { CellPack } from '../../extensions/cellpack';
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
import { Asset } from '../../mol-util/assets';
import { ObjectKeys } from '../../mol-util/type-helpers';
import { PluginState } from '../../mol-plugin/state';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
import { Color } from '../../mol-util/color';
import { StateObjectSelector } from '../../mol-state';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { Mp4Export } from '../../extensions/mp4-export';
import { StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
import { CreateJoleculeState } from './extensions/jolecule';
import { LoadCellPackModel } from './extensions/cellpack/model';
import { StructureFromCellpack } from './extensions/cellpack/state';
require('mol-plugin/skin/light.scss')
require('mol-plugin-ui/skin/light.scss');
function getParam(name: string, regex: string): string {
let r = new RegExp(`${name}=(${regex})[&]?`, 'i');
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
}
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setProductionMode, setDebugMode } from '../../mol-util/debug';
const hideControls = getParam('hide-controls', `[^&]+`) === '1';
const CustomFormats = [
['g3d', G3dProvider] as const
];
const Extensions = {
'cellpack': PluginSpec.Behavior(CellPack),
'dnatco-confal-pyramids': PluginSpec.Behavior(DnatcoConfalPyramids),
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
'rcsb-assembly-symmetry': PluginSpec.Behavior(RCSBAssemblySymmetry),
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
'g3d': PluginSpec.Behavior(G3DFormat),
'mp4-export': PluginSpec.Behavior(Mp4Export)
};
const DefaultViewerOptions = {
customFormats: CustomFormats as [string, DataFormatProvider][],
extensions: ObjectKeys(Extensions),
layoutIsExpanded: true,
layoutShowControls: true,
layoutShowRemoteState: true,
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
layoutShowSequence: true,
layoutShowLog: true,
layoutShowLeftPanel: true,
disableAntialiasing: false,
pixelScale: 1,
enableWboit: true,
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
};
type ViewerOptions = typeof DefaultViewerOptions;
export class Viewer {
plugin: PluginContext
constructor(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
const o = { ...DefaultViewerOptions, ...options };
const defaultSpec = DefaultPluginSpec();
const spec: PluginSpec = {
actions: [...defaultSpec.actions],
behaviors: [
...defaultSpec.behaviors,
...o.extensions.map(e => Extensions[e]),
],
animations: [...defaultSpec.animations || []],
customParamEditors: defaultSpec.customParamEditors,
customFormats: o?.customFormats,
layout: {
initial: {
isExpanded: o.layoutIsExpanded,
showControls: o.layoutShowControls,
controlsDisplay: o.layoutControlsDisplay,
},
controls: {
...defaultSpec.layout && defaultSpec.layout.controls,
top: o.layoutShowSequence ? undefined : 'none',
bottom: o.layoutShowLog ? undefined : 'none',
left: o.layoutShowLeftPanel ? undefined : 'none',
}
function init() {
const spec: PluginSpec = {
actions: [
...DefaultPluginSpec.actions,
PluginSpec.Action(CreateJoleculeState),
PluginSpec.Action(LoadCellPackModel),
PluginSpec.Action(StructureFromCellpack),
],
behaviors: [...DefaultPluginSpec.behaviors],
animations: [...DefaultPluginSpec.animations || []],
customParamEditors: DefaultPluginSpec.customParamEditors,
layout: {
initial: {
isExpanded: true,
showControls: !hideControls
},
components: {
...defaultSpec.components,
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
},
config: [
[PluginConfig.General.DisableAntialiasing, o.disableAntialiasing],
[PluginConfig.General.PixelScale, o.pixelScale],
[PluginConfig.General.EnableWboit, o.enableWboit],
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
[PluginConfig.State.DefaultServer, o.pluginStateServer],
[PluginConfig.State.CurrentServer, o.pluginStateServer],
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
[PluginConfig.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider]
]
};
const element = typeof elementOrId === 'string'
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
this.plugin = createPlugin(element, spec);
}
setRemoteSnapshot(id: string) {
const url = `${this.plugin.config.get(PluginConfig.State.CurrentServer)}/get/${id}`;
return PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
}
loadSnapshotFromUrl(url: string, type: PluginState.SnapshotType) {
return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
}
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'url',
params: {
url: Asset.Url(url),
format: format as any,
isBinary,
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
}
controls: {
...DefaultPluginSpec.layout && DefaultPluginSpec.layout.controls
}
}));
}
async loadAllModelsOrAssemblyFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const plugin = this.plugin;
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'all-models', { useDefaultIfSingleModel: true, representationPresetParams: options?.representationParams });
}
async loadStructureFromData(data: string | number[], format: BuiltInTrajectoryFormat, options?: { dataLabel?: string }) {
const _data = await this.plugin.builders.data.rawData({ data, label: options?.dataLabel });
const trajectory = await this.plugin.builders.structure.parseTrajectory(_data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default');
}
loadPdb(pdb: string, options?: LoadStructureOptions) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
const provider = this.plugin.config.get(PluginConfig.Download.DefaultPdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'pdb' as const,
params: {
provider: {
id: pdb,
server: {
name: provider,
params: PdbDownloadProvider[provider].defaultValue as any
}
},
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
}
}
}));
}
loadPdbDev(pdbDev: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'pdb-dev' as const,
params: {
provider: {
id: pdbDev,
encoding: 'bcif',
},
options: params.source.params.options,
}
}
}));
}
loadEmdb(emdb: string, options?: { detail?: number }) {
const provider = this.plugin.config.get(PluginConfig.Download.DefaultEmdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
source: {
name: 'pdb-emd-ds' as const,
params: {
provider: {
id: emdb,
server: provider,
},
detail: options?.detail ?? 3,
}
}
}));
}
async loadVolumeFromUrl(url: string, format: BuildInVolumeFormat, isBinary: boolean, isovalues: VolumeIsovalueInfo[], entryId?: string) {
const plugin = this.plugin;
if (!plugin.dataFormats.get(format)) {
throw new Error(`Unknown density format: ${format}`);
}
};
const plugin = createPlugin(document.getElementById('app')!, spec);
trySetSnapshot(plugin);
}
return plugin.dataTransaction(async () => {
const data = await plugin.builders.data.download({ url, isBinary, label: entryId }, { state: { isGhost: true } });
const parsed = await plugin.dataFormats.get(format)!.parse(plugin, data, { entryId });
const volume = (parsed.volume || parsed.volumes[0]) as StateObjectSelector<PluginStateObject.Volume.Data>;
if (!volume?.isOk) throw new Error('Failed to parse any volume.');
const repr = plugin.build().to(volume);
for (const iso of isovalues) {
repr.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, volume.data!, {
type: 'isosurface',
typeParams: { alpha: iso.alpha ?? 1, isoValue: iso.type === 'absolute' ? { kind: 'absolute', absoluteValue: iso.value } : { kind: 'relative', relativeValue: iso.value } },
color: 'uniform',
colorParams: { value: iso.color }
}));
}
await repr.commit();
});
}
handleResize() {
this.plugin.layout.events.updated.next();
async function trySetSnapshot(ctx: PluginContext) {
try {
const snapshotUrl = getParam('snapshot-url', `[^&]+`);
const snapshotId = getParam('snapshot-id', `[^&]+`);
if (!snapshotUrl && !snapshotId) return;
// TODO parametrize the server
const url = snapshotId
? `https://webchem.ncbr.muni.cz/molstar-state/get/${snapshotId}`
: snapshotUrl;
await PluginCommands.State.Snapshots.Fetch.dispatch(ctx, { url })
} catch (e) {
ctx.log.error('Failed to load snapshot.');
console.warn('Failed to load snapshot', e);
}
}
export interface LoadStructureOptions {
representationParams?: StructureRepresentationPresetProvider.CommonParams
}
export interface VolumeIsovalueInfo {
type: 'absolute' | 'relative',
value: number,
color: Color,
alpha?: number
}
init();

View File

@@ -1,73 +0,0 @@
#!/usr/bin/env node
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Josh McMenemy <josh.mcmenemy@gmail.com>
*/
import * as argparse from 'argparse';
import * as path from 'path';
import util from 'util';
import fs from 'fs';
require('util.promisify').shim();
const writeFile = util.promisify(fs.writeFile);
import { DatabaseCollection } from '../../mol-data/db';
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
import { ensureDataAvailable, readCCD } from './util';
function extractIonNames(ccd: DatabaseCollection<CCD_Schema>) {
const ionNames: string[] = [];
for (const k in ccd) {
const {chem_comp} = ccd[k];
if (chem_comp.name.value(0).toUpperCase().includes(' ION')) {
ionNames.push(chem_comp.id.value(0));
}
}
// these are extra ions that don't have ION in their name
ionNames.push('NCO', 'OHX');
return ionNames;
}
function writeIonNamesFile(filePath: string, ionNames: string[]) {
const output = `/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated ion names params file. Names extracted from CCD components.
*
* @author molstar/chem-comp-dict/create-table cli
*/
export const IonNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});
`;
writeFile(filePath, output);
}
async function run(out: string, forceDownload = false) {
await ensureDataAvailable(forceDownload);
const ccd = await readCCD();
const ionNames = extractIonNames(ccd);
if (!fs.existsSync(path.dirname(out))) {
fs.mkdirSync(path.dirname(out));
}
writeIonNamesFile(out, ionNames);
}
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Extract and save IonNames from CCD.'
});
parser.addArgument('out', {
help: 'Generated file output path.'
});
parser.addArgument([ '--forceDownload', '-f' ], {
action: 'storeTrue',
help: 'Force download of CCD and PVCD.'
});
interface Args {
out: string,
forceDownload?: boolean,
}
const args: Args = parser.parseArgs();
run(args.out, args.forceDownload);

View File

@@ -1,294 +0,0 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
import * as util from 'util';
import * as path from 'path';
import * as fs from 'fs';
require('util.promisify').shim();
const writeFile = util.promisify(fs.writeFile);
import { Database, Table, DatabaseCollection } from '../../mol-data/db';
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
import { SetUtils } from '../../mol-util/set';
import { DefaultMap } from '../../mol-util/map';
import { mmCIF_chemCompBond_schema } from '../../mol-io/reader/cif/schema/mmcif-extras';
import { ccd_chemCompAtom_schema } from '../../mol-io/reader/cif/schema/ccd-extras';
import { ensureDataAvailable, getEncodedCif, readCCD, readPVCD } from './util';
type CCB = Table<CCD_Schema['chem_comp_bond']>
type CCA = Table<CCD_Schema['chem_comp_atom']>
function ccbKey(compId: string, atomId1: string, atomId2: string) {
return atomId1 < atomId2 ? `${compId}:${atomId1}-${atomId2}` : `${compId}:${atomId2}-${atomId1}`;
}
function ccaKey(compId: string, atomId: string) {
return `${compId}:${atomId}`;
}
function addChemCompBondToSet(set: Set<string>, ccb: CCB) {
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
set.add(ccbKey(ccb.comp_id.value(i), ccb.atom_id_1.value(i), ccb.atom_id_2.value(i)));
}
return set;
}
function addChemCompAtomToSet(set: Set<string>, cca: CCA) {
for (let i = 0, il = cca._rowCount; i < il; ++i) {
set.add(ccaKey(cca.comp_id.value(i), cca.atom_id.value(i)));
}
return set;
}
function checkAddingBondsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
const ccbSetByParent = DefaultMap<string, Set<string>>(() => new Set());
for (const k in pvcd) {
const { chem_comp, chem_comp_bond } = pvcd[k];
if (chem_comp_bond._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
if (parentIds.length === 0) {
const set = ccbSetByParent.getDefault(chem_comp.id.value(0));
addChemCompBondToSet(set, chem_comp_bond);
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
const parentId = parentIds[i];
const set = ccbSetByParent.getDefault(parentId);
addChemCompBondToSet(set, chem_comp_bond);
}
}
}
}
for (const k in pvcd) {
const { chem_comp, chem_comp_atom, chem_comp_bond } = pvcd[k];
if (chem_comp_bond._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
if (parentIds.length > 0) {
for (let i = 0, il = parentIds.length; i < il; ++i) {
const entryBonds = addChemCompBondToSet(new Set<string>(), chem_comp_bond);
const entryAtoms = addChemCompAtomToSet(new Set<string>(), chem_comp_atom);
const extraBonds = SetUtils.difference(ccbSetByParent.get(parentIds[i])!, entryBonds);
extraBonds.forEach(bk => {
const [a1, a2] = bk.split('|');
if (entryAtoms.has(a1) && entryAtoms.has(a2)) {
console.error(`Adding all PVCD bonds would wrongly add bond ${bk} for ${k}`);
}
});
}
}
}
}
}
function checkAddingAtomsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
const ccaSetByParent = DefaultMap<string, Set<string>>(() => new Set());
for (const k in pvcd) {
const { chem_comp, chem_comp_atom } = pvcd[k];
if (chem_comp_atom._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
if (parentIds.length === 0) {
const set = ccaSetByParent.getDefault(chem_comp.id.value(0));
addChemCompAtomToSet(set, chem_comp_atom);
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
const parentId = parentIds[i];
const set = ccaSetByParent.getDefault(parentId);
addChemCompAtomToSet(set, chem_comp_atom);
}
}
}
}
}
async function createBonds(
ccd: DatabaseCollection<CCD_Schema>,
pvcd: DatabaseCollection<CCD_Schema>,
atomsRequested: boolean
) {
const ccbSet = new Set<string>();
const comp_id: string[] = [];
const atom_id_1: string[] = [];
const atom_id_2: string[] = [];
const value_order: typeof mmCIF_chemCompBond_schema['value_order']['T'][] = [];
const pdbx_aromatic_flag: typeof mmCIF_chemCompBond_schema['pdbx_aromatic_flag']['T'][] = [];
const pdbx_stereo_config: typeof mmCIF_chemCompBond_schema['pdbx_stereo_config']['T'][] = [];
const molstar_protonation_variant: string[] = [];
function addBonds(compId: string, ccb: CCB, protonationVariant: boolean) {
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
const atomId1 = ccb.atom_id_1.value(i);
const atomId2 = ccb.atom_id_2.value(i);
const k = ccbKey(compId, atomId1, atomId2);
if (!ccbSet.has(k)) {
atom_id_1.push(atomId1);
atom_id_2.push(atomId2);
comp_id.push(compId);
value_order.push(ccb.value_order.value(i));
pdbx_aromatic_flag.push(ccb.pdbx_aromatic_flag.value(i));
pdbx_stereo_config.push(ccb.pdbx_stereo_config.value(i));
molstar_protonation_variant.push(protonationVariant ? 'Y' : 'N');
ccbSet.add(k);
}
}
}
// check adding bonds from PVCD
checkAddingBondsFromPVCD(pvcd);
// add bonds from PVCD
for (const k in pvcd) {
const { chem_comp, chem_comp_bond } = pvcd[k];
if (chem_comp_bond._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
if (parentIds.length === 0) {
addBonds(chem_comp.id.value(0), chem_comp_bond, false);
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
addBonds(parentIds[i], chem_comp_bond, true);
}
}
}
}
// add bonds from CCD
for (const k in ccd) {
const { chem_comp, chem_comp_bond } = ccd[k];
if (chem_comp_bond._rowCount) {
addBonds(chem_comp.id.value(0), chem_comp_bond, false);
}
}
const bondTable = Table.ofArrays(mmCIF_chemCompBond_schema, {
comp_id, atom_id_1, atom_id_2, value_order,
pdbx_aromatic_flag, pdbx_stereo_config, molstar_protonation_variant
});
const bondDatabase = Database.ofTables(
CCB_TABLE_NAME,
{ chem_comp_bond: mmCIF_chemCompBond_schema },
{ chem_comp_bond: bondTable }
);
return { bonds: bondDatabase, atoms: atomsRequested ? createAtoms(ccd, pvcd) : void 0 };
}
function createAtoms(ccd: DatabaseCollection<CCD_Schema>, pvcd: DatabaseCollection<CCD_Schema>) {
const ccaSet = new Set<string>();
const comp_id: string[] = [];
const atom_id: string[] = [];
const charge: number[] = [];
const pdbx_stereo_config: typeof CCD_Schema.chem_comp_atom['pdbx_stereo_config']['T'][] = [];
function addAtoms(compId: string, cca: CCA) {
for (let i = 0, il = cca._rowCount; i < il; ++i) {
const atomId = cca.atom_id.value(i);
const k = ccaKey(compId, atomId);
if (!ccaSet.has(k)) {
atom_id.push(atomId);
comp_id.push(compId);
charge.push(cca.charge.value(i));
pdbx_stereo_config.push(cca.pdbx_stereo_config.value(i));
ccaSet.add(k);
}
}
}
// check adding atoms from PVCD
checkAddingAtomsFromPVCD(pvcd);
// add atoms from PVCD
for (const k in pvcd) {
const { chem_comp, chem_comp_atom } = pvcd[k];
if (chem_comp_atom._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
if (parentIds.length === 0) {
addAtoms(chem_comp.id.value(0), chem_comp_atom);
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
addAtoms(parentIds[i], chem_comp_atom);
}
}
}
}
// add atoms from CCD
for (const k in ccd) {
const { chem_comp, chem_comp_atom } = ccd[k];
if (chem_comp_atom._rowCount) {
addAtoms(chem_comp.id.value(0), chem_comp_atom);
}
}
const atomTable = Table.ofArrays(ccd_chemCompAtom_schema, {
comp_id, atom_id, charge, pdbx_stereo_config
});
return Database.ofTables(
CCA_TABLE_NAME,
{ chem_comp_atom: ccd_chemCompAtom_schema },
{ chem_comp_atom: atomTable }
);
}
async function run(out: string, binary = false, forceDownload = false, ccaOut?: string) {
await ensureDataAvailable(forceDownload);
const ccd = await readCCD();
const pvcd = await readPVCD();
const { bonds, atoms } = await createBonds(ccd, pvcd, !!ccaOut);
const ccbCif = getEncodedCif(CCB_TABLE_NAME, bonds, binary);
if (!fs.existsSync(path.dirname(out))) {
fs.mkdirSync(path.dirname(out));
}
writeFile(out, ccbCif);
if (!!ccaOut) {
const ccaCif = getEncodedCif(CCA_TABLE_NAME, atoms, binary);
if (!fs.existsSync(path.dirname(ccaOut))) {
fs.mkdirSync(path.dirname(ccaOut));
}
writeFile(ccaOut, ccaCif);
}
}
const CCB_TABLE_NAME = 'CHEM_COMP_BONDS';
const CCA_TABLE_NAME = 'CHEM_COMP_ATOMS';
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Create a cif file with one big table of all chem_comp_bond entries from the CCD and PVCD.'
});
parser.addArgument('out', {
help: 'Generated file output path.'
});
parser.addArgument([ '--forceDownload', '-f' ], {
action: 'storeTrue',
help: 'Force download of CCD and PVCD.'
});
parser.addArgument([ '--binary', '-b' ], {
action: 'storeTrue',
help: 'Output as BinaryCIF.'
});
parser.addArgument(['--ccaOut', '-a'], {
help: 'Optional generated file output path for chem_comp_atom data.',
required: false
});
interface Args {
out: string,
forceDownload?: boolean,
binary?: boolean,
ccaOut?: string
}
const args: Args = parser.parseArgs();
run(args.out, args.binary, args.forceDownload, args.ccaOut);

View File

@@ -1,75 +0,0 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as util from 'util';
import * as path from 'path';
import * as fs from 'fs';
import * as zlib from 'zlib';
import fetch from 'node-fetch';
require('util.promisify').shim();
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);
import { Progress } from '../../mol-task';
import { Database } from '../../mol-data/db';
import { CIF } from '../../mol-io/reader/cif';
import { CifWriter } from '../../mol-io/writer/cif';
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
export async function ensureAvailable(path: string, url: string, forceDownload = false) {
if (forceDownload || !fs.existsSync(path)) {
console.log(`downloading ${url}...`);
const data = await fetch(url);
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR);
}
if (url.endsWith('.gz')) {
await writeFile(path, zlib.gunzipSync(await data.buffer()));
} else {
await writeFile(path, await data.text());
}
console.log(`done downloading ${url}`);
}
}
export async function ensureDataAvailable(forceDownload = false) {
await ensureAvailable(CCD_PATH, CCD_URL, forceDownload);
await ensureAvailable(PVCD_PATH, PVCD_URL, forceDownload);
}
export async function readFileAsCollection<S extends Database.Schema>(path: string, schema: S) {
const parsed = await parseCif(await readFile(path, 'utf8'));
return CIF.toDatabaseCollection(schema, parsed.result);
}
export async function readCCD() {
return readFileAsCollection(CCD_PATH, CCD_Schema);
}
export async function readPVCD() {
return readFileAsCollection(PVCD_PATH, CCD_Schema);
}
async function parseCif(data: string | Uint8Array) {
const comp = CIF.parse(data);
console.time('parse cif');
const parsed = await comp.run(p => console.log(Progress.format(p)), 250);
console.timeEnd('parse cif');
if (parsed.isError) throw parsed;
return parsed;
}
export function getEncodedCif(name: string, database: Database<Database.Schema>, binary = false) {
const encoder = CifWriter.createEncoder({ binary, encoderName: 'mol*' });
CifWriter.Encoder.writeDatabase(encoder, name, database);
return encoder.getData();
}
const DATA_DIR = path.join(__dirname, '..', '..', '..', '..', 'build/data');
const CCD_PATH = path.join(DATA_DIR, 'components.cif');
const PVCD_PATH = path.join(DATA_DIR, 'aa-variants-v1.cif');
const CCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif';
const PVCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/aa-variants-v1.cif';

View File

@@ -1,119 +0,0 @@
/**
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
import { CIF, CifCategory, getCifFieldType, CifField, CifFile } from '../../mol-io/reader/cif';
import { CifWriter, EncodingStrategyHint } from '../../mol-io/writer/cif';
import * as util from 'util';
import * as fs from 'fs';
import * as zlib from 'zlib';
import { Progress, Task, RuntimeContext } from '../../mol-task';
import { classifyFloatArray, classifyIntArray } from '../../mol-io/common/binary-cif';
import { BinaryEncodingProvider } from '../../mol-io/writer/cif/encoder/binary';
import { Category } from '../../mol-io/writer/cif/encoder';
import { ReaderResult } from '../../mol-io/reader/result';
function showProgress(p: Progress) {
process.stdout.write(`\r${new Array(80).join(' ')}`);
process.stdout.write(`\r${Progress.format(p)}`);
}
const readFileAsync = util.promisify(fs.readFile);
const unzipAsync = util.promisify<zlib.InputType, Buffer>(zlib.unzip);
async function readFile(ctx: RuntimeContext, filename: string): Promise<ReaderResult<CifFile>> {
const isGz = /\.gz$/i.test(filename);
if (filename.match(/\.bcif/)) {
let input = await readFileAsync(filename);
if (isGz) input = await unzipAsync(input);
return await CIF.parseBinary(new Uint8Array(input)).runInContext(ctx);
} else {
let str: string;
if (isGz) {
const data = await unzipAsync(await readFileAsync(filename));
str = data.toString('utf8');
} else {
str = await readFileAsync(filename, 'utf8');
}
return await CIF.parseText(str).runInContext(ctx);
}
}
async function getCIF(ctx: RuntimeContext, filename: string) {
const parsed = await readFile(ctx, filename);
if (parsed.isError) {
throw new Error(parsed.toString());
}
return parsed.result;
}
function getCategoryInstanceProvider(cat: CifCategory, fields: CifWriter.Field[]): CifWriter.Category {
return {
name: cat.name,
instance: () => CifWriter.categoryInstance(fields, { data: cat, rowCount: cat.rowCount })
};
}
function classify(name: string, field: CifField): CifWriter.Field {
const type = getCifFieldType(field);
if (type['@type'] === 'str') {
return { name, type: CifWriter.Field.Type.Str, value: field.str, valueKind: field.valueKind };
} else if (type['@type'] === 'float') {
const encoder = classifyFloatArray(field.toFloatArray({ array: Float64Array }));
return CifWriter.Field.float(name, field.float, { valueKind: field.valueKind, encoder, typedArray: Float64Array });
} else {
const encoder = classifyIntArray(field.toIntArray({ array: Int32Array }));
return CifWriter.Field.int(name, field.int, { valueKind: field.valueKind, encoder, typedArray: Int32Array });
}
}
export function convert(path: string, asText = false, hints?: EncodingStrategyHint[], filter?: string) {
return Task.create<Uint8Array>('BinaryCIF', async ctx => {
const encodingProvider: BinaryEncodingProvider = hints
? CifWriter.createEncodingProviderFromJsonConfig(hints)
: { get: (c, f) => void 0 };
const cif = await getCIF(ctx, path);
const encoder = CifWriter.createEncoder({
binary: !asText,
encoderName: 'mol*/ciftools cif2bcif',
binaryAutoClassifyEncoding: true,
binaryEncodingPovider: encodingProvider
});
if (filter) {
encoder.setFilter(Category.filterOf(filter));
}
let maxProgress = 0;
for (const b of cif.blocks) {
maxProgress += b.categoryNames.length;
for (const c of b.categoryNames) maxProgress += b.categories[c].fieldNames.length;
}
let current = 0;
for (const b of cif.blocks) {
encoder.startDataBlock(b.header);
for (const c of b.categoryNames) {
const cat = b.categories[c];
const fields: CifWriter.Field[] = [];
for (const f of cat.fieldNames) {
fields.push(classify(f, cat.getField(f)!));
current++;
if (ctx.shouldUpdate) await ctx.update({ message: 'Encoding...', current, max: maxProgress });
}
encoder.writeCategory(getCategoryInstanceProvider(b.categories[c], fields));
current++;
if (ctx.shouldUpdate) await ctx.update({ message: 'Encoding...', current, max: maxProgress });
}
}
await ctx.update('Exporting...');
const ret = encoder.getData() as Uint8Array;
await ctx.update('Done.\n');
return ret;
}).run(showProgress, 250);
}

View File

@@ -1,68 +0,0 @@
#!/usr/bin/env node
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
import * as util from 'util';
import * as fs from 'fs';
import * as zlib from 'zlib';
import { convert } from './converter';
require('util.promisify').shim();
async function process(srcPath: string, outPath: string, configPath?: string, filterPath?: string) {
const config = configPath ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : void 0;
const filter = filterPath ? fs.readFileSync(filterPath, 'utf8') : void 0;
const res = await convert(srcPath, false, config, filter);
await write(outPath, res);
}
const zipAsync = util.promisify<zlib.InputType, Buffer>(zlib.gzip);
async function write(outPath: string, res: Uint8Array) {
const isGz = /\.gz$/i.test(outPath);
if (isGz) {
res = await zipAsync(res);
}
fs.writeFileSync(outPath, res);
}
function run(args: Args) {
process(args.src, args.out, args.config, args.filter);
}
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Convert any CIF file to a BCIF file'
});
parser.addArgument([ 'src' ], {
help: 'Source CIF path'
});
parser.addArgument([ 'out' ], {
help: 'Output BCIF path'
});
parser.addArgument([ '-c', '--config' ], {
help: 'Optional encoding strategy/precision config path',
required: false
});
parser.addArgument([ '-f', '--filter' ], {
help: 'Optional filter whitelist/blacklist path',
required: false
});
interface Args {
src: string
out: string
config?: string
filter?: string
}
const args: Args = parser.parseArgs();
if (args) {
run(args);
}

View File

@@ -1,275 +0,0 @@
#!/usr/bin/env node
/**
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
import * as fs from 'fs';
import * as path from 'path';
import fetch from 'node-fetch';
import { parseCsv } from '../../mol-io/reader/csv/parser';
import { CifFrame, CifBlock } from '../../mol-io/reader/cif';
import { parseCifText } from '../../mol-io/reader/cif/text/parser';
import { generateSchema } from './util/cif-dic';
import { generate } from './util/generate';
import { Filter, Database } from './util/schema';
import { parseImportGet } from './util/helper';
function getDicVersion(block: CifBlock) {
return block.categories.dictionary.getField('version')!.str(0);
}
function getDicNamespace(block: CifBlock) {
return block.categories.dictionary.getField('namespace')!.str(0);
}
async function runGenerateSchemaMmcif(name: string, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
await ensureMmcifDicAvailable();
const mmcifDic = await parseCifText(fs.readFileSync(MMCIF_DIC_PATH, 'utf8')).run();
if (mmcifDic.isError) throw mmcifDic;
await ensureIhmDicAvailable();
const ihmDic = await parseCifText(fs.readFileSync(IHM_DIC_PATH, 'utf8')).run();
if (ihmDic.isError) throw ihmDic;
await ensureCarbBranchDicAvailable();
const carbBranchDic = await parseCifText(fs.readFileSync(CARB_BRANCH_DIC_PATH, 'utf8')).run();
if (carbBranchDic.isError) throw carbBranchDic;
await ensureCarbCompDicAvailable();
const carbCompDic = await parseCifText(fs.readFileSync(CARB_COMP_DIC_PATH, 'utf8')).run();
if (carbCompDic.isError) throw carbCompDic;
const mmcifDicVersion = getDicVersion(mmcifDic.result.blocks[0]);
const ihmDicVersion = getDicVersion(ihmDic.result.blocks[0]);
const carbDicVersion = 'draft';
const version = `Dictionary versions: mmCIF ${mmcifDicVersion}, IHM ${ihmDicVersion}, CARB ${carbDicVersion}.`;
const frames: CifFrame[] = [...mmcifDic.result.blocks[0].saveFrames, ...ihmDic.result.blocks[0].saveFrames, ...carbBranchDic.result.blocks[0].saveFrames, ...carbCompDic.result.blocks[0].saveFrames];
const schema = generateSchema(frames);
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
}
async function runGenerateSchemaCifCore(name: string, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
await ensureCifCoreDicAvailable();
const cifCoreDic = await parseCifText(fs.readFileSync(CIF_CORE_DIC_PATH, 'utf8')).run();
if (cifCoreDic.isError) throw cifCoreDic;
const cifCoreDicVersion = getDicVersion(cifCoreDic.result.blocks[0]);
const version = `Dictionary versions: CifCore ${cifCoreDicVersion}.`;
const frames: CifFrame[] = [...cifCoreDic.result.blocks[0].saveFrames];
const imports = await resolveImports(frames, DIC_DIR);
const schema = generateSchema(frames, imports);
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
}
async function resolveImports(frames: CifFrame[], baseDir: string): Promise<Map<string, CifFrame[]>> {
const imports = new Map<string, CifFrame[]>();
for (const d of frames) {
if ('import' in d.categories) {
const importGet = parseImportGet(d.categories['import'].getField('get')!.str(0));
for (const g of importGet) {
const { file } = g;
if (!file) continue;
if (imports.has(file)) continue;
const dic = await parseCifText(fs.readFileSync(path.join(baseDir, file), 'utf8')).run();
if (dic.isError) throw dic;
imports.set(file, [...dic.result.blocks[0].saveFrames]);
}
}
}
return imports;
}
async function runGenerateSchemaDic(name: string, dicPath: string, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
const dic = await parseCifText(fs.readFileSync(dicPath, 'utf8')).run();
if (dic.isError) throw dic;
const dicVersion = getDicVersion(dic.result.blocks[0]);
const dicName = getDicNamespace(dic.result.blocks[0]);
const version = `Dictionary versions: ${dicName} ${dicVersion}.`;
const frames: CifFrame[] = [...dic.result.blocks[0].saveFrames];
const imports = await resolveImports(frames, path.dirname(dicPath));
const schema = generateSchema(frames, imports);
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
}
async function runGenerateSchema(name: string, version: string, schema: Database, fieldNamesPath: string, typescript = false, out: string, moldbImportPath: string, addAliases: boolean) {
const filter = fieldNamesPath ? await getFieldNamesFilter(fieldNamesPath) : undefined;
const output = typescript ? generate(name, version, schema, filter, moldbImportPath, addAliases) : JSON.stringify(schema, undefined, 4);
if (out) {
fs.writeFileSync(out, output);
} else {
console.log(output);
}
}
async function getFieldNamesFilter(fieldNamesPath: string): Promise<Filter> {
const fieldNamesStr = fs.readFileSync(fieldNamesPath, 'utf8');
const parsed = await parseCsv(fieldNamesStr, { noColumnNames: true }).run();
if (parsed.isError) throw parser.error;
const csvFile = parsed.result;
const fieldNamesCol = csvFile.table.getColumn('0');
if (!fieldNamesCol) throw 'error getting fields columns';
const fieldNames = fieldNamesCol.toStringArray();
const filter: Filter = {};
fieldNames.forEach((name, i) => {
const [ category, field ] = name.split('.');
// console.log(category, field)
if (!filter[ category ]) filter[ category ] = {};
filter[ category ][ field ] = true;
});
return filter;
}
async function ensureMmcifDicAvailable() { await ensureDicAvailable(MMCIF_DIC_PATH, MMCIF_DIC_URL); }
async function ensureIhmDicAvailable() { await ensureDicAvailable(IHM_DIC_PATH, IHM_DIC_URL); }
async function ensureCarbBranchDicAvailable() { await ensureDicAvailable(CARB_BRANCH_DIC_PATH, CARB_BRANCH_DIC_URL); }
async function ensureCarbCompDicAvailable() { await ensureDicAvailable(CARB_COMP_DIC_PATH, CARB_COMP_DIC_URL); }
async function ensureCifCoreDicAvailable() {
await ensureDicAvailable(CIF_CORE_DIC_PATH, CIF_CORE_DIC_URL);
await ensureDicAvailable(CIF_CORE_ENUM_PATH, CIF_CORE_ENUM_URL);
await ensureDicAvailable(CIF_CORE_ATTR_PATH, CIF_CORE_ATTR_URL);
}
async function ensureDicAvailable(dicPath: string, dicUrl: string) {
if (FORCE_DIC_DOWNLOAD || !fs.existsSync(dicPath)) {
const name = dicUrl.substr(dicUrl.lastIndexOf('/') + 1);
console.log(`downloading ${name}...`);
const data = await fetch(dicUrl);
if (!fs.existsSync(DIC_DIR)) {
fs.mkdirSync(DIC_DIR);
}
fs.writeFileSync(dicPath, await data.text());
console.log(`done downloading ${name}`);
}
}
const DIC_DIR = path.resolve(__dirname, '../../../../build/dics/');
const MMCIF_DIC_PATH = `${DIC_DIR}/mmcif_pdbx_v50.dic`;
const MMCIF_DIC_URL = 'http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic';
const IHM_DIC_PATH = `${DIC_DIR}/ihm-extension.dic`;
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHM-dictionary/master/ihm-extension.dic';
const CARB_BRANCH_DIC_PATH = `${DIC_DIR}/entity_branch-extension.dic`;
const CARB_BRANCH_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/entity_branch-extension.dic';
const CARB_COMP_DIC_PATH = `${DIC_DIR}/chem_comp-extension.dic`;
const CARB_COMP_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/chem_comp-extension.dic';
const CIF_CORE_DIC_PATH = `${DIC_DIR}/cif_core.dic`;
const CIF_CORE_DIC_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/cif_core.dic';
const CIF_CORE_ENUM_PATH = `${DIC_DIR}/templ_enum.cif`;
const CIF_CORE_ENUM_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/templ_enum.cif';
const CIF_CORE_ATTR_PATH = `${DIC_DIR}/templ_attr.cif`;
const CIF_CORE_ATTR_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/templ_attr.cif';
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Create schema from mmcif dictionary (v50 plus IHM and entity_branch extensions, downloaded from wwPDB)'
});
parser.addArgument([ '--preset', '-p' ], {
defaultValue: '',
choices: ['', 'mmCIF', 'CCD', 'BIRD', 'CifCore'],
help: 'Preset name'
});
parser.addArgument([ '--name', '-n' ], {
defaultValue: '',
help: 'Schema name'
});
parser.addArgument([ '--out', '-o' ], {
help: 'Generated schema output path, if not given printed to stdout'
});
parser.addArgument([ '--targetFormat', '-tf' ], {
defaultValue: 'typescript-molstar',
choices: ['typescript-molstar', 'json-internal'],
help: 'Target format'
});
parser.addArgument([ '--dicPath', '-d' ], {
defaultValue: '',
help: 'Path to dictionary'
});
parser.addArgument([ '--fieldNamesPath', '-fn' ], {
defaultValue: '',
help: 'Field names to include'
});
parser.addArgument([ '--forceDicDownload', '-f' ], {
action: 'storeTrue',
help: 'Force download of dictionaries'
});
parser.addArgument([ '--moldataImportPath', '-mip' ], {
defaultValue: 'molstar/lib/mol-data',
help: 'mol-data import path (for typescript target only)'
});
parser.addArgument([ '--addAliases', '-aa' ], {
action: 'storeTrue',
help: 'Add field name/path aliases'
});
interface Args {
name: string
preset: '' | 'mmCIF' | 'CCD' | 'BIRD' | 'CifCore'
forceDicDownload: boolean
dic: '' | 'mmCIF' | 'CifCore'
dicPath: string,
fieldNamesPath: string
targetFormat: 'typescript-molstar' | 'json-internal'
out: string,
moldataImportPath: string
addAliases: boolean
}
const args: Args = parser.parseArgs();
const FORCE_DIC_DOWNLOAD = args.forceDicDownload;
switch (args.preset) {
case 'mmCIF':
args.name = 'mmCIF';
args.dic = 'mmCIF';
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/mmcif-field-names.csv');
break;
case 'CCD':
args.name = 'CCD';
args.dic = 'mmCIF';
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/ccd-field-names.csv');
break;
case 'BIRD':
args.name = 'BIRD';
args.dic = 'mmCIF';
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/bird-field-names.csv');
break;
case 'CifCore':
args.name = 'CifCore';
args.dic = 'CifCore';
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/cif-core-field-names.csv');
break;
}
if (args.name) {
const typescript = args.targetFormat === 'typescript-molstar';
if (args.dicPath) {
runGenerateSchemaDic(args.name, args.dicPath, args.fieldNamesPath, typescript, args.out, args.moldataImportPath, args.addAliases).catch(e => {
console.error(e);
});
} else if (args.dic === 'mmCIF') {
runGenerateSchemaMmcif(args.name, args.fieldNamesPath, typescript, args.out, args.moldataImportPath, args.addAliases).catch(e => {
console.error(e);
});
} else if (args.dic === 'CifCore') {
runGenerateSchemaCifCore(args.name, args.fieldNamesPath, typescript, args.out, args.moldataImportPath, args.addAliases).catch(e => {
console.error(e);
});
}
}

View File

@@ -1,475 +0,0 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Database, Column, EnumCol, StrCol, IntCol, ListCol, FloatCol, CoordCol, MatrixCol, VectorCol } from './schema';
import { parseImportGet } from './helper';
import * as Data from '../../../mol-io/reader/cif/data-model';
import { CifFrame } from '../../../mol-io/reader/cif/data-model';
export function getFieldType(type: string, description: string, values?: string[], container?: string): Column {
switch (type) {
// mmCIF
case 'code':
case 'ucode':
case 'line':
case 'uline':
case 'text':
case 'char':
case 'uchar3':
case 'uchar1':
case 'boolean':
return values && values.length ? EnumCol(values, 'str', description) : StrCol(description);
case 'aliasname':
case 'name':
case 'idname':
case 'any':
case 'atcode':
case 'fax':
case 'phone':
case 'email':
case 'code30':
case 'seq-one-letter-code':
case 'author':
case 'orcid_id':
case 'sequence_dep':
case 'pdb_id':
case 'emd_id':
// todo, consider adding specialised fields
case 'yyyy-mm-dd':
case 'yyyy-mm-dd:hh:mm':
case 'yyyy-mm-dd:hh:mm-flex':
case 'int-range':
case 'float-range':
case 'binary':
case 'operation_expression':
case 'point_symmetry':
case '4x3_matrix':
case '3x4_matrices':
case 'point_group':
case 'point_group_helical':
case 'symmetry_operation':
case 'date_dep':
case 'url':
case 'symop':
case 'exp_data_doi':
case 'asym_id':
return StrCol(description);
case 'int':
case 'non_negative_int':
case 'positive_int':
return values && values.length ? EnumCol(values, 'int', description) : IntCol(description);
case 'float':
return FloatCol(description);
case 'ec-type':
case 'ucode-alphanum-csv':
case 'id_list':
return ListCol('str', ',', description);
case 'id_list_spc':
return ListCol('str', ' ', description);
// cif
case 'Text':
case 'Code':
case 'Complex':
case 'Symop':
case 'List':
case 'List(Real,Real)':
case 'List(Real,Real,Real,Real)':
case 'Date':
case 'Datetime':
case 'Tag':
case 'Implied':
return wrapContainer('str', ',', description, container);
case 'Real':
return wrapContainer('float', ',', description, container);
case 'Integer':
return wrapContainer('int', ',', description, container);
}
console.log(`unknown type '${type}'`);
return StrCol(description);
}
function ColFromType(type: 'int' | 'str' | 'float' | 'coord', description: string): Column {
switch (type) {
case 'int': return IntCol(description);
case 'str': return StrCol(description);
case 'float': return FloatCol(description);
case 'coord': return CoordCol(description);
}
}
function wrapContainer(type: 'int' | 'str' | 'float' | 'coord', separator: string, description: string, container?: string) {
return container && container === 'List' ? ListCol(type, separator, description) : ColFromType(type, description);
}
type FrameCategories = { [category: string]: Data.CifFrame }
type FrameLinks = { [k: string]: string }
interface FrameData {
categories: FrameCategories
links: FrameLinks
}
type Imports = Map<string, CifFrame[]>
function getImportFrames(d: Data.CifFrame, imports: Imports) {
const frames: Data.CifFrame[] = [];
if (!('import' in d.categories)) return frames;
const importGet = parseImportGet(d.categories['import'].getField('get')!.str(0));
for (const g of importGet) {
const { file, save } = g;
if (!file || !save) {
console.warn(`missing 'save' or 'file' for import in '${d.header}'`);
continue;
}
const importFrames = imports.get(file);
if (!importFrames) {
console.warn(`missing '${file}' entry in imports`);
continue;
}
const importSave = importFrames.find(id => id.header.toLowerCase() === save.toLowerCase());
if (!importSave) {
console.warn(`missing '${save}' save frame in '${file}'`);
continue;
}
frames.push(importSave);
}
return frames;
}
/** get field from given or linked category */
function getField(category: string, field: string, d: Data.CifFrame, imports: Imports, ctx: FrameData): Data.CifField|undefined {
const { categories, links } = ctx;
const cat = d.categories[category];
if (cat) {
return cat.getField(field);
} else if (d.header in links) {
const linkName = links[d.header];
if (linkName in categories) {
return getField(category, field, categories[linkName], imports, ctx);
} else {
// console.log(`link '${linkName}' not found`)
}
} else {
const importFrames = getImportFrames(d, imports);
for (const idf of importFrames) {
return getField(category, field, idf, imports, ctx);
}
}
}
function getEnums(d: Data.CifFrame, imports: Imports, ctx: FrameData) {
const value = getField('item_enumeration', 'value', d, imports, ctx);
const enums: string[] = [];
if (value) {
for (let i = 0; i < value.rowCount; ++i) {
enums.push(value.str(i));
// console.log(value.str(i))
}
return enums;
} else {
// console.log(`item_enumeration.value not found for '${d.header}'`)
}
}
function getContainer(d: Data.CifFrame, imports: Imports, ctx: FrameData) {
const value = getField('type', 'container', d, imports, ctx);
return value ? value.str(0) : undefined;
}
function getCode(d: Data.CifFrame, imports: Imports, ctx: FrameData): [string, string[] | undefined, string | undefined ] | undefined {
const code = getField('item_type', 'code', d, imports, ctx) || getField('type', 'contents', d, imports, ctx);
if (code) {
return [ code.str(0), getEnums(d, imports, ctx), getContainer(d, imports, ctx) ];
} else {
console.log(`item_type.code or type.contents not found for '${d.header}'`);
}
}
function getSubCategory(d: Data.CifFrame, imports: Imports, ctx: FrameData): string | undefined {
const value = getField('item_sub_category', 'id', d, imports, ctx);
if (value) {
return value.str(0);
}
}
function getDescription(d: Data.CifFrame, imports: Imports, ctx: FrameData): string | undefined {
const value = getField('item_description', 'description', d, imports, ctx) || getField('description', 'text', d, imports, ctx);
if (value) {
// trim (after newlines) and remove references to square brackets
return value.str(0).trim()
.replace(/(\r\n|\r|\n)([ \t]+)/g, '\n')
.replace(/(\[[1-3]\])+ element/, 'elements')
.replace(/(\[[1-3]\])+/, '');
}
}
function getAliases(d: Data.CifFrame, imports: Imports, ctx: FrameData): string[] | undefined {
const value = getField('item_aliases', 'alias_name', d, imports, ctx) || getField('alias', 'definition_id', d, imports, ctx);
return value ? value.toStringArray().map(v => v.substr(1)) : undefined;
}
const reMatrixField = /\[[1-3]\]\[[1-3]\]/;
const reVectorField = /\[[1-3]\]/;
const FORCE_INT_FIELDS = [
'_atom_site.id',
'_atom_site.auth_seq_id',
'_atom_site_anisotrop.id',
'_pdbx_struct_mod_residue.auth_seq_id',
'_struct_conf.beg_auth_seq_id',
'_struct_conf.end_auth_seq_id',
'_struct_conn.ptnr1_auth_seq_id',
'_struct_conn.ptnr2_auth_seq_id',
'_struct_sheet_range.beg_auth_seq_id',
'_struct_sheet_range.end_auth_seq_id',
];
const FORCE_MATRIX_FIELDS_MAP: { [k: string]: string } = {
'atom_site_aniso.U_11': 'U',
'atom_site_aniso.U_22': 'U',
'atom_site_aniso.U_33': 'U',
'atom_site_aniso.U_23': 'U',
'atom_site_aniso.U_13': 'U',
'atom_site_aniso.U_12': 'U',
'atom_site_aniso.U_11_su': 'U_su',
'atom_site_aniso.U_22_su': 'U_su',
'atom_site_aniso.U_33_su': 'U_su',
'atom_site_aniso.U_23_su': 'U_su',
'atom_site_aniso.U_13_su': 'U_su',
'atom_site_aniso.U_12_su': 'U_su',
};
const FORCE_MATRIX_FIELDS = Object.keys(FORCE_MATRIX_FIELDS_MAP);
const EXTRA_ALIASES: Database['aliases'] = {
'atom_site_aniso.U': [
'atom_site_anisotrop_U'
],
'atom_site_aniso.U_su': [
'atom_site_aniso_U_esd',
'atom_site_anisotrop_U_esd',
],
};
const COMMA_SEPARATED_LIST_FIELDS = [
'_atom_site.pdbx_struct_group_id',
'_chem_comp.mon_nstd_parent_comp_id',
'_diffrn_radiation.pdbx_wavelength_list',
'_diffrn_source.pdbx_wavelength_list',
'_em_diffraction.tilt_angle_list', // 20,40,50,55
'_em_entity_assembly.entity_id_list',
'_entity.pdbx_description', // Endolysin,Beta-2 adrenergic receptor
'_entity.pdbx_ec',
'_entity_poly.pdbx_strand_id', // A,B
'_entity_src_gen.pdbx_gene_src_gene', // ADRB2, ADRB2R, B2AR
'_pdbx_depui_entry_details.experimental_methods',
'_pdbx_depui_entry_details.requested_accession_types',
'_pdbx_soln_scatter_model.software_list', // INSIGHT II, HOMOLOGY, DISCOVERY, BIOPOLYMER, DELPHI
'_pdbx_soln_scatter_model.software_author_list', // MSI
'_pdbx_soln_scatter_model.entry_fitting_list', // Odd example: 'PDB CODE 1HFI, 1HCC, 1HFH, 1VCC'
'_pdbx_struct_assembly_gen.entity_inst_id',
'_pdbx_struct_assembly_gen.asym_id_list',
'_pdbx_struct_assembly_gen.auth_asym_id_list',
'_pdbx_struct_assembly_gen_depositor_info.asym_id_list',
'_pdbx_struct_assembly_gen_depositor_info.chain_id_list',
'_pdbx_struct_group_list.group_enumeration_type',
'_reflns.pdbx_diffrn_id',
'_refine.pdbx_diffrn_id',
'_reflns_shell.pdbx_diffrn_id',
'_struct_keywords.text',
];
const SPACE_SEPARATED_LIST_FIELDS = [
'_chem_comp.pdbx_subcomponent_list', // TSM DPH HIS CHF EMR
'_pdbx_soln_scatter.data_reduction_software_list', // OTOKO
'_pdbx_soln_scatter.data_analysis_software_list', // SCTPL5 GNOM
];
const SEMICOLON_SEPARATED_LIST_FIELDS = [
'_chem_comp.pdbx_synonyms' // GLYCERIN; PROPANE-1,2,3-TRIOL
];
/**
* Useful when a dictionary extension will add enum values to an existing dictionary.
* By adding them here, the dictionary extension can be tested before the added enum
* values are available in the existing dictionary.
*/
const EXTRA_ENUM_VALUES: { [k: string]: string[] } = {
};
export function generateSchema(frames: CifFrame[], imports: Imports = new Map()): Database {
const tables: Database['tables'] = {};
const aliases: Database['aliases'] = { ...EXTRA_ALIASES };
const categories: FrameCategories = {};
const links: FrameLinks = {};
const ctx = { categories, links };
// get category metadata
frames.forEach(d => {
// category definitions in mmCIF start with '_' and don't include a '.'
// category definitions in cifCore don't include a '.'
if (d.header[0] === '_' || d.header.includes('.')) return;
const categoryName = d.header.toLowerCase();
// console.log(d.header, d.categoryNames, d.categories)
let descriptionField: Data.CifField | undefined;
const categoryKeyNames = new Set<string>();
if ('category' in d.categories && 'category_key' in d.categories) {
const category = d.categories['category'];
const categoryKey = d.categories['category_key'];
if (categoryKey) {
const categoryKey_names = categoryKey.getField('name');
if (categoryKey_names) {
for (let i = 0, il = categoryKey_names.rowCount; i < il; ++i) {
categoryKeyNames.add(categoryKey_names.str(i));
}
}
}
descriptionField = category.getField('description');
if (categoryKeyNames.size === 0) {
console.log(`no key given for category '${categoryName}'`);
}
}
if ('description' in d.categories) {
descriptionField = d.categories['description'].getField('text');
}
let description = '';
if (descriptionField) {
description = descriptionField.str(0).trim()
.replace(/(\r\n|\r|\n)([ \t]+)/g, '\n'); // remove padding after newlines
} else {
console.log(`no description given for category '${categoryName}'`);
}
tables[categoryName] = { description, key: categoryKeyNames, columns: {} };
// console.log('++++++++++++++++++++++++++++++++++++++++++')
// console.log('name', categoryName)
// console.log('desc', description)
// console.log('key', categoryKeyNames)
});
// build list of links between categories
frames.forEach(d => {
if (d.header[0] !== '_' && !d.header.includes('.')) return;
categories[d.header] = d;
const item_linked = d.categories['item_linked'];
if (item_linked) {
const child_name = item_linked.getField('child_name');
const parent_name = item_linked.getField('parent_name');
if (child_name && parent_name) {
for (let i = 0; i < item_linked.rowCount; ++i) {
const childName = child_name.str(i);
const parentName = parent_name.str(i);
if (childName in links && links[childName] !== parentName) {
console.log(`${childName} linked to ${links[childName]}, ignoring link to ${parentName}`);
}
links[childName] = parentName;
}
}
}
});
// get field data
Object.keys(categories).forEach(fullName => {
const d = categories[fullName];
if (!d) {
console.log(`'${fullName}' not found, moving on`);
return;
}
const categoryName = d.header.substring(d.header[0] === '_' ? 1 : 0, d.header.indexOf('.'));
const itemName = d.header.substring(d.header.indexOf('.') + 1);
let fields: { [k: string]: Column };
if (categoryName in tables) {
fields = tables[categoryName].columns;
tables[categoryName].key.add(itemName);
} else if (categoryName.toLowerCase() in tables) {
// take case from category name in 'field' data as it is better if data is from cif dictionaries
tables[categoryName] = tables[categoryName.toLowerCase()];
fields = tables[categoryName].columns;
} else {
console.log(`category '${categoryName}' has no metadata`);
fields = {};
tables[categoryName] = {
description: '',
key: new Set(),
columns: fields
};
}
const itemAliases = getAliases(d, imports, ctx);
if (itemAliases) aliases[`${categoryName}.${itemName}`] = itemAliases;
const description = getDescription(d, imports, ctx) || '';
// need to use regex to check for matrix or vector items
// as sub_category assignment is missing for some entries
const subCategory = getSubCategory(d, imports, ctx);
if (subCategory === 'cartesian_coordinate' || subCategory === 'fractional_coordinate') {
fields[itemName] = CoordCol(description);
} else if (FORCE_INT_FIELDS.includes(d.header)) {
fields[itemName] = IntCol(description);
console.log(`forcing int: ${d.header}`);
} else if (FORCE_MATRIX_FIELDS.includes(d.header)) {
fields[itemName] = FloatCol(description);
fields[FORCE_MATRIX_FIELDS_MAP[d.header]] = MatrixCol(3, 3, description);
console.log(`forcing matrix: ${d.header}`);
} else if (subCategory === 'matrix') {
fields[itemName.replace(reMatrixField, '')] = MatrixCol(3, 3, description);
} else if (subCategory === 'vector') {
fields[itemName.replace(reVectorField, '')] = VectorCol(3, description);
} else {
if (itemName.match(reMatrixField)) {
fields[itemName.replace(reMatrixField, '')] = MatrixCol(3, 3, description);
console.log(`${d.header} should have 'matrix' _item_sub_category.id`);
} else if (itemName.match(reVectorField)) {
fields[itemName.replace(reVectorField, '')] = VectorCol(3, description);
console.log(`${d.header} should have 'vector' _item_sub_category.id`);
} else {
const code = getCode(d, imports, ctx);
if (code) {
let fieldType = getFieldType(code[0], description, code[1], code[2]);
if (fieldType.type === 'str') {
if (COMMA_SEPARATED_LIST_FIELDS.includes(d.header)) {
fieldType = ListCol('str', ',', description);
console.log(`forcing comma separated: ${d.header}`);
} else if (SPACE_SEPARATED_LIST_FIELDS.includes(d.header)) {
fieldType = ListCol('str', ' ', description);
console.log(`forcing space separated: ${d.header}`);
} else if (SEMICOLON_SEPARATED_LIST_FIELDS.includes(d.header)) {
fieldType = ListCol('str', ';', description);
console.log(`forcing space separated: ${d.header}`);
}
}
if (d.header in EXTRA_ENUM_VALUES) {
if (fieldType.type === 'enum') {
fieldType.values.push(...EXTRA_ENUM_VALUES[d.header]);
} else {
console.warn(`expected enum: ${d.header}`);
}
}
fields[itemName] = fieldType;
} else {
fields[itemName] = StrCol(description);
// console.log(`could not determine code for '${d.header}'`)
}
}
}
});
return { tables, aliases };
}

View File

@@ -1,151 +0,0 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Database, Filter, Column } from './schema';
import { indentString } from '../../../mol-util/string';
import { FieldPath } from '../../../mol-io/reader/cif/schema';
function header (name: string, info: string, moldataImportPath: string) {
return `/**
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated '${name}' schema file. ${info}
*
* @author molstar/ciftools package
*/
import { Database, Column } from '${moldataImportPath}/db';
import Schema = Column.Schema;`;
}
function footer (name: string) {
return `
export type ${name}_Schema = typeof ${name}_Schema;
export interface ${name}_Database extends Database<${name}_Schema> {};`;
}
function getTypeShorthands(schema: Database, fields?: Filter) {
const types = new Set<string>();
Object.keys(schema.tables).forEach(table => {
if (fields && !fields[table]) return;
const { columns } = schema.tables[table];
Object.keys(columns).forEach(columnName => {
if (fields && !fields[table][columnName]) return;
types.add(schema.tables[table].columns[columnName].type);
});
});
const shorthands: string[] = [];
types.forEach(type => {
switch (type) {
case 'str': shorthands.push('const str = Schema.str;'); break;
case 'int': shorthands.push('const int = Schema.int;'); break;
case 'float': shorthands.push('const float = Schema.float;'); break;
case 'coord': shorthands.push('const coord = Schema.coord;'); break;
case 'enum': shorthands.push('const Aliased = Schema.Aliased;'); break;
case 'matrix': shorthands.push('const Matrix = Schema.Matrix;'); break;
case 'vector': shorthands.push('const Vector = Schema.Vector;'); break;
case 'list': shorthands.push('const List = Schema.List;'); break;
}
});
return shorthands.join('\n');
}
function getTypeDef(c: Column): string {
switch (c.type) {
case 'str': return 'str';
case 'int': return 'int';
case 'float': return 'float';
case 'coord': return 'coord';
case 'enum':
return `Aliased<'${c.values.map(v => v.replace(/'/g, '\\\'')).join(`' | '`)}'>(${c.subType})`;
case 'matrix':
return `Matrix(${c.rows}, ${c.columns})`;
case 'vector':
return `Vector(${c.length})`;
case 'list':
if (c.subType === 'int') {
return `List('${c.separator}', x => parseInt(x, 10))`;
} else if (c.subType === 'float' || c.subType === 'coord') {
return `List('${c.separator}', x => parseFloat(x))`;
} else {
return `List('${c.separator}', x => x)`;
}
}
}
const reSafePropertyName = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
function safePropertyString(name: string) { return name.match(reSafePropertyName) ? name : `'${name}'`; }
function doc(description: string, spacesCount: number) {
const spaces = ' '.repeat(spacesCount);
return [
`${spaces}/**`,
`${indentString(description, 1, `${spaces} * `)}`.replace(/ +\n/g, '\n'),
`${spaces} */`
].join('\n');
}
export function generate (name: string, info: string, schema: Database, fields: Filter | undefined, moldataImportPath: string, addAliases: boolean) {
const codeLines: string[] = [];
if (fields) {
Object.keys(fields).forEach(table => {
if (table in schema.tables) {
const schemaTable = schema.tables[table];
Object.keys(fields[table]).forEach(column => {
if (!(column in schemaTable.columns)) {
console.log(`filter field '${table}.${column}' not found in schema`);
}
});
} else {
console.log(`filter category '${table}' not found in schema`);
}
});
}
codeLines.push(`export const ${name}_Schema = {`);
Object.keys(schema.tables).forEach(table => {
if (fields && !fields[table]) return;
const { description, columns } = schema.tables[table];
if (description) codeLines.push(doc(description, 4));
codeLines.push(` ${safePropertyString(table)}: {`);
Object.keys(columns).forEach(columnName => {
if (fields && !fields[table][columnName]) return;
const c = columns[columnName];
const typeDef = getTypeDef(c);
if (c.description) codeLines.push(doc(c.description, 8));
codeLines.push(` ${safePropertyString(columnName)}: ${typeDef},`);
});
codeLines.push(' },');
});
codeLines.push('};');
if (addAliases) {
codeLines.push('');
codeLines.push(`export const ${name}_Aliases = {`);
Object.keys(schema.aliases).forEach(path => {
const [ table, columnName ] = path.split('.');
if (fields && !fields[table]) return;
if (fields && !fields[table][columnName]) return;
const filteredAliases = new Set<string>();
schema.aliases[path].forEach(p => {
if (!FieldPath.equal(p, path)) filteredAliases.add(FieldPath.canonical(p));
});
if (filteredAliases.size === 0) return;
codeLines.push(` ${safePropertyString(path)}: [`);
filteredAliases.forEach(alias => {
codeLines.push(` '${alias}',`);
});
codeLines.push(' ],');
});
codeLines.push('};');
}
return `${header(name, info, moldataImportPath)}\n\n${getTypeShorthands(schema, fields)}\n\n${codeLines.join('\n')}\n${footer(name)}`;
}

View File

@@ -1,20 +0,0 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export type Import = { save?: string, file?: string }
export function parseImportGet(s: string): Import[] {
// [{'save':hi_ang_Fox_coeffs 'file':templ_attr.cif} {'save':hi_ang_Fox_c0 'file':templ_enum.cif}]
// [{"file":'templ_enum.cif' "save":'H_M_ref'}]
return s.trim().substring(2, s.length - 2).split(/}[ \n\t]*{/g).map(s => {
const save = s.match(/('save'|"save"):([^ \t\n]+)/);
const file = s.match(/('file'|"file"):([^ \t\n]+)/);
return {
save: save ? save[0].substr(7).replace(/['"]/g, '') : undefined,
file: file ? file[0].substr(7).replace(/['"]/g, '') : undefined
};
});
}

View File

@@ -1,77 +0,0 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export interface Database {
tables: { [ tableName: string ]: Table }
aliases: { [ path: string ]: string[] }
}
export interface Table {
description: string
key: Set<string>
columns: { [ columnName: string ]: Column }
}
export type Column = IntCol | StrCol | FloatCol | CoordCol | EnumCol | VectorCol | MatrixCol | ListCol
type BaseCol = { description: string }
export type IntCol = { type: 'int' } & BaseCol
export function IntCol(description: string): IntCol { return { type: 'int', description }; }
export type StrCol = { type: 'str' } & BaseCol
export function StrCol(description: string): StrCol { return { type: 'str', description }; }
export type FloatCol = { type: 'float' } & BaseCol
export function FloatCol(description: string): FloatCol { return { type: 'float', description }; }
export type CoordCol = { type: 'coord' } & BaseCol
export function CoordCol(description: string): CoordCol { return { type: 'coord', description }; }
export type EnumCol = { type: 'enum', subType: 'int' | 'str', values: string[] } & BaseCol
export function EnumCol(values: string[], subType: 'int' | 'str', description: string): EnumCol {
return { type: 'enum', description, values, subType };
}
export type VectorCol = { type: 'vector', length: number } & BaseCol
export function VectorCol(length: number, description: string): VectorCol {
return { type: 'vector', description, length };
}
export type MatrixCol = { type: 'matrix', rows: number, columns: number } & BaseCol
export function MatrixCol(columns: number, rows: number, description: string): MatrixCol {
return { type: 'matrix', description, columns, rows };
}
export type ListCol = { type: 'list', subType: 'int' | 'str' | 'float' | 'coord', separator: string } & BaseCol
export function ListCol(subType: 'int' | 'str' | 'float' | 'coord', separator: string, description: string): ListCol {
return { type: 'list', description, separator, subType };
}
export type Filter = { [ table: string ]: { [ column: string ]: true } }
export function mergeFilters (...filters: Filter[]) {
const n = filters.length;
const mergedFilter: Filter = {};
const fields: Map<string, number> = new Map();
filters.forEach(filter => {
Object.keys(filter).forEach(category => {
Object.keys(filter[ category ]).forEach(field => {
const key = `${category}.${field}`;
const value = fields.get(key) || 0;
fields.set(key, value + 1);
});
});
});
fields.forEach((v, k) => {
if (v !== n) return;
const [categoryName, fieldName] = k.split('.');
if (categoryName in mergedFilter) {
mergedFilter[categoryName][fieldName] = true;
} else {
mergedFilter[categoryName] = { fieldName: true };
}
});
return mergedFilter;
}

View File

@@ -1,93 +0,0 @@
#!/usr/bin/env node
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
import * as fs from 'fs';
import * as path from 'path';
import fetch from 'node-fetch';
import { UniqueArray } from '../../mol-data/generic';
const LIPIDS_DIR = path.resolve(__dirname, '../../../../build/lipids/');
const MARTINI_LIPIDS_PATH = path.resolve(LIPIDS_DIR, 'martini_lipids.itp');
const MARTINI_LIPIDS_URL = 'http://www.cgmartini.nl/images/parameters/lipids/Collections/martini_v2.0_lipids_all_201506.itp';
async function ensureAvailable(path: string, url: string) {
if (FORCE_DOWNLOAD || !fs.existsSync(path)) {
const name = url.substr(url.lastIndexOf('/') + 1);
console.log(`downloading ${name}...`);
const data = await fetch(url);
if (!fs.existsSync(LIPIDS_DIR)) {
fs.mkdirSync(LIPIDS_DIR);
}
fs.writeFileSync(path, await data.text());
console.log(`done downloading ${name}`);
}
}
async function ensureLipidsAvailable() { await ensureAvailable(MARTINI_LIPIDS_PATH, MARTINI_LIPIDS_URL); }
const extraLipids = ['DMPC'];
async function run(out: string) {
await ensureLipidsAvailable();
const lipidsItpStr = fs.readFileSync(MARTINI_LIPIDS_PATH, 'utf8');
const lipids = UniqueArray.create<string>();
const reLipid = /\[moleculetype\]\n; molname nrexcl\n +([a-zA-Z]{3,5})/g;
let m: RegExpExecArray | null;
while ((m = reLipid.exec(lipidsItpStr)) !== null) {
const v = m[0].substr(m[0].lastIndexOf(' ') + 1);
UniqueArray.add(lipids, v, v);
}
for (const v of extraLipids) {
UniqueArray.add(lipids, v, v);
}
const lipidNames = JSON.stringify(lipids.array);
if (out) {
const output = `/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated lipid params file. Names extracted from Martini FF lipids itp.
*
* @author molstar/lipid-params cli
*/
export const LipidNames = new Set(${lipidNames.replace(/"/g, "'").replace(/,/g, ', ')});
`;
fs.writeFileSync(out, output);
} else {
console.log(lipidNames);
}
}
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Create lipid params (from martini lipids itp)'
});
parser.addArgument([ '--out', '-o' ], {
help: 'Generated lipid params output path, if not given printed to stdout'
});
parser.addArgument([ '--forceDownload', '-f' ], {
action: 'storeTrue',
help: 'Force download of martini lipids itp'
});
interface Args {
out: string
forceDownload: boolean
}
const args: Args = parser.parseArgs();
const FORCE_DOWNLOAD = args.forceDownload;
run(args.out || '').catch(e => {
console.error(e);
});

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { AlphaOrbitalsExample } from '.';
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior';
import { PluginContextContainer } from '../../mol-plugin-ui/plugin';
export function mountControls(orbitals: AlphaOrbitalsExample, parent: Element) {
ReactDOM.render(<PluginContextContainer plugin={orbitals.plugin}>
<Controls orbitals={orbitals} />
</PluginContextContainer>, parent);
}
function Controls({ orbitals }: { orbitals: AlphaOrbitalsExample }) {
const params = useBehavior(orbitals.params);
const values = useBehavior(orbitals.state);
return <ParameterControls params={params as any} values={values} onChangeValues={(vs: any) => orbitals.state.next(vs)} />;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<title>Mol* Alpha Orbitals Example</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#app {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
#controls {
position: absolute;
left: 8px;
top: 8px;
width: 300px;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
<div id="app"></div>
<div id='controls'></div>
<script>
AlphaOrbitalsExample.init('app')
</script>
</body>
</html>

View File

@@ -1,213 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/spherical-functions';
import { BasisAndOrbitals, CreateOrbitalDensityVolume, CreateOrbitalRepresentation3D, CreateOrbitalVolume, StaticBasisAndOrbitals } from '../../extensions/alpha-orbitals/transforms';
import { createPluginAsync } from '../../mol-plugin';
import { DefaultPluginSpec } from '../../mol-plugin/spec';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { PluginConfig } from '../../mol-plugin/config';
import { PluginContext } from '../../mol-plugin/context';
import { StateObjectSelector, StateTransformer } from '../../mol-state';
import { Color } from '../../mol-util/color';
import { ColorNames } from '../../mol-util/color/names';
import { ParamDefinition } from '../../mol-util/param-definition';
import { mountControls } from './controls';
import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
import { BehaviorSubject } from 'rxjs';
import { debounceTime, skip } from 'rxjs/operators';
import './index.html';
import { Basis, AlphaOrbital } from '../../extensions/alpha-orbitals/data-model';
import { PluginCommands } from '../../mol-plugin/commands';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
require('mol-plugin-ui/skin/light.scss');
interface DemoInput {
moleculeSdf: string,
basis: Basis,
order: SphericalBasisOrder,
orbitals: AlphaOrbital[]
}
interface Params {
show: { name: 'orbital', params: { index: number } } | { name: 'density', params: {} },
isoValue: number,
gpuSurface: boolean
}
type Selectors = {
type: 'orbital',
volume: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalVolume>,
positive: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
negative: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
} | {
type: 'density',
volume: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalDensityVolume>,
positive: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
}
export class AlphaOrbitalsExample {
plugin: PluginContext;
async init(target: string | HTMLElement) {
this.plugin = await createPluginAsync(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginSpec(),
layout: {
initial: {
isExpanded: false,
showControls: false
},
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' },
},
config: [
[PluginConfig.Viewport.ShowExpand, false],
[PluginConfig.Viewport.ShowControls, false],
[PluginConfig.Viewport.ShowSelectionMode, false],
[PluginConfig.Viewport.ShowAnimation, false],
]
});
this.plugin.managers.interactivity.setProps({ granularity: 'element' });
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
PluginCommands.Toast.Show(this.plugin, {
title: 'Error',
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
});
return;
}
this.load({
moleculeSdf: DemoMoleculeSDF,
...DemoOrbitals
});
mountControls(this, document.getElementById('controls')!);
}
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);
readonly state = new BehaviorSubject<Params>({ show: { name: 'orbital', params: { index: 32 } }, isoValue: 1, gpuSurface: false });
private selectors?: Selectors = void 0;
private basis?: StateObjectSelector<BasisAndOrbitals> = void 0;
private currentParams: Params = { ...this.state.value };
private clearVolume() {
if (!this.selectors) return;
const v = this.selectors.volume;
this.selectors = void 0;
return this.plugin.build().delete(v).commit();
}
private async syncVolume() {
if (!this.basis?.isOk) return;
const state = this.state.value;
if (state.show.name !== this.selectors?.type) {
await this.clearVolume();
}
const update = this.plugin.build();
if (state.show.name === 'orbital') {
if (!this.selectors) {
const volume = update
.to(this.basis)
.apply(CreateOrbitalVolume, { index: state.show.params.index });
const positive = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('positive', ColorNames.blue)).selector;
const negative = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('negative', ColorNames.red)).selector;
this.selectors = { type: 'orbital', volume: volume.selector, positive, negative };
} else {
const index = state.show.params.index;
update.to(this.selectors.volume).update(CreateOrbitalVolume, () => ({ index }));
}
} else {
if (!this.selectors) {
const volume = update
.to(this.basis)
.apply(CreateOrbitalDensityVolume);
const positive = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('positive', ColorNames.blue)).selector;
this.selectors = { type: 'density', volume: volume.selector, positive };
}
}
await update.commit();
if (this.currentParams.gpuSurface !== this.state.value.gpuSurface) {
await this.setIsovalue();
}
this.currentParams = this.state.value;
}
private setIsovalue() {
if (!this.selectors) return;
this.currentParams = this.state.value;
const update = this.plugin.build();
update.to(this.selectors.positive).update(this.volumeParams('positive', ColorNames.blue));
if (this.selectors?.type === 'orbital') {
update.to(this.selectors.negative).update(this.volumeParams('negative', ColorNames.red));
}
return update.commit();
}
private volumeParams(kind: 'positive' | 'negative', color: Color): StateTransformer.Params<typeof CreateOrbitalRepresentation3D> {
return {
alpha: 0.85,
color,
directVolume: this.state.value.gpuSurface,
kind,
relativeIsovalue: this.state.value.isoValue,
pickable: false,
xrayShaded: true
};
}
async load(input: DemoInput) {
await this.plugin.clear();
const data = await this.plugin.builders.data.rawData({ data: input.moleculeSdf }, { state: { isGhost: true } });
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, 'mol');
const model = await this.plugin.builders.structure.createModel(trajectory);
const structure = await this.plugin.builders.structure.createStructure(model);
const all = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'all');
if (all) await this.plugin.builders.structure.representation.addRepresentation(all, { type: 'ball-and-stick', color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } });
this.basis = await this.plugin.build().toRoot()
.apply(StaticBasisAndOrbitals, { basis: input.basis, order: input.order, orbitals: input.orbitals })
.commit();
await this.syncVolume();
this.params.next({
show: ParamDefinition.MappedStatic('orbital', {
'orbital': ParamDefinition.Group({
index: ParamDefinition.Numeric(32, { min: 0, max: input.orbitals.length - 1 }, { immediateUpdate: true, isEssential: true }),
}),
'density': ParamDefinition.EmptyGroup()
}, { cycle: true }),
isoValue: ParamDefinition.Numeric(this.currentParams.isoValue, { min: 0.5, max: 3, step: 0.1 }, { immediateUpdate: true, isEssential: false }),
gpuSurface: ParamDefinition.Boolean(this.currentParams.gpuSurface, { isHidden: true })
});
this.state.pipe(skip(1), debounceTime(1000 / 24)).subscribe(async params => {
if (params.show.name !== this.currentParams.show.name
|| (params.show.name === 'orbital' && this.currentParams.show.name === 'orbital' && params.show.params.index !== this.currentParams.show.params.index)) {
this.syncVolume();
} else if (params.isoValue !== this.currentParams.isoValue || params.gpuSurface !== this.currentParams.gpuSurface) {
this.setIsovalue();
}
});
}
}
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();

View File

@@ -1,16 +0,0 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { PluginUIComponent } from '../../mol-plugin-ui/base';
import * as React from 'react';
export class CustomToastMessage extends PluginUIComponent {
render() {
return <>
Custom <i>Toast</i> content. No timeout.
</>;
}
}

View File

@@ -1,168 +0,0 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { EmptyLoci } from '../../mol-model/loci';
import { StructureSelection } from '../../mol-model/structure';
import { createPlugin } from '../../mol-plugin';
import { DefaultPluginSpec } from '../../mol-plugin/spec';
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginContext } from '../../mol-plugin/context';
import { Script } from '../../mol-script/script';
import { Color } from '../../mol-util/color';
import { StripedResidues } from './coloring';
import { CustomToastMessage } from './controls';
import './index.html';
import { buildStaticSuperposition, dynamicSuperpositionTest, StaticSuperpositionTestData } from './superposition';
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
import { Asset } from '../../mol-util/assets';
require('mol-plugin-ui/skin/light.scss');
type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: boolean, assemblyId?: string }
class BasicWrapper {
plugin: PluginContext;
init(target: string | HTMLElement) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginSpec(),
layout: {
initial: {
isExpanded: false,
showControls: false
},
controls: {
// left: 'none'
}
},
components: {
remoteState: 'none'
}
});
this.plugin.representation.structure.themes.colorThemeRegistry.add(StripedResidues.colorThemeProvider!);
this.plugin.managers.lociLabels.addProvider(StripedResidues.labelProvider!);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider, true);
}
async load({ url, format = 'mmcif', isBinary = false, assemblyId = '' }: LoadParams) {
await this.plugin.clear();
const data = await this.plugin.builders.data.download({ url: Asset.Url(url), isBinary }, { state: { isGhost: true } });
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default', {
structure: assemblyId ? {
name: 'assembly',
params: { id: assemblyId }
} : {
name: 'model',
params: { }
},
showUnitcell: false,
representationPreset: 'auto'
});
}
setBackground(color: number) {
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: props => { props.renderer.backgroundColor = Color(color); } });
}
toggleSpin() {
if (!this.plugin.canvas3d) return;
PluginCommands.Canvas3D.SetSettings(this.plugin, {
settings: props => {
props.trackball.spin = !props.trackball.spin;
}
});
if (!this.plugin.canvas3d.props.trackball.spin) PluginCommands.Camera.Reset(this.plugin, {});
}
private animateModelIndexTargetFps() {
return Math.max(1, this.animate.modelIndex.targetFps | 0);
}
animate = {
modelIndex: {
targetFps: 8,
onceForward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'forward' } } }); },
onceBackward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'backward' } } }); },
palindrome: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'palindrome', params: {} } }); },
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: {} } }); },
stop: () => this.plugin.managers.animation.stop()
}
}
coloring = {
applyStripes: async () => {
this.plugin.dataTransaction(async () => {
for (const s of this.plugin.managers.structure.hierarchy.current.structures) {
await this.plugin.managers.structure.component.updateRepresentationsTheme(s.components, { color: StripedResidues.propertyProvider.descriptor.name as any });
}
});
},
applyDefault: async () => {
this.plugin.dataTransaction(async () => {
for (const s of this.plugin.managers.structure.hierarchy.current.structures) {
await this.plugin.managers.structure.component.updateRepresentationsTheme(s.components, { color: 'default' });
}
});
}
}
interactivity = {
highlightOn: () => {
const data = this.plugin.managers.structure.hierarchy.current.structures[0]?.cell.obj?.data;
if (!data) return;
const seq_id = 7;
const sel = Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
'residue-test': Q.core.rel.eq([Q.struct.atomProperty.macromolecular.label_seq_id(), seq_id]),
'group-by': Q.struct.atomProperty.macromolecular.residueKey()
}), data);
const loci = StructureSelection.toLociWithSourceUnits(sel);
this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci });
},
clearHighlight: () => {
this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
}
}
tests = {
staticSuperposition: async () => {
await this.plugin.clear();
return buildStaticSuperposition(this.plugin, StaticSuperpositionTestData);
},
dynamicSuperposition: async () => {
await this.plugin.clear();
return dynamicSuperpositionTest(this.plugin, ['1tqn', '2hhb', '4hhb'], 'HEM');
},
toggleValidationTooltip: () => {
return this.plugin.state.updateBehavior(PDBeStructureQualityReport, params => { params.showTooltip = !params.showTooltip; });
},
showToasts: () => {
PluginCommands.Toast.Show(this.plugin, {
title: 'Toast 1',
message: 'This is an example text, timeout 3s',
key: 'toast-1',
timeoutMs: 3000
});
PluginCommands.Toast.Show(this.plugin, {
title: 'Toast 2',
message: CustomToastMessage,
key: 'toast-2'
});
},
hideToasts: () => {
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-1' });
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-2' });
}
}
}
(window as any).BasicMolStarWrapper = new BasicWrapper();

View File

@@ -1,119 +0,0 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Mat4 } from '../../mol-math/linear-algebra';
import { QueryContext, StructureSelection } from '../../mol-model/structure';
import { superpose } from '../../mol-model/structure/structure/util/superposition';
import { PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { PluginContext } from '../../mol-plugin/context';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { Expression } from '../../mol-script/language/expression';
import { compile } from '../../mol-script/runtime/query/compiler';
import { StateObjectRef } from '../../mol-state';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { Asset } from '../../mol-util/assets';
export type SuperpositionTestInput = {
pdbId: string,
auth_asym_id: string,
matrix: Mat4
}[];
export function buildStaticSuperposition(plugin: PluginContext, src: SuperpositionTestInput) {
return plugin.dataTransaction(async () => {
for (const s of src) {
const { structure } = await loadStructure(plugin, `https://www.ebi.ac.uk/pdbe/static/entry/${s.pdbId}_updated.cif`, 'mmcif');
await transform(plugin, structure, s.matrix);
const chain = await plugin.builders.structure.tryCreateComponentFromExpression(structure, chainSelection(s.auth_asym_id), `Chain ${s.auth_asym_id}`);
if (chain) await plugin.builders.structure.representation.addRepresentation(chain, { type: 'cartoon' });
}
});
}
export const StaticSuperpositionTestData: SuperpositionTestInput = [
{
pdbId: '1aj5', auth_asym_id: 'A', matrix: Mat4.identity()
},
{
pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows([
[0.406, 0.879, 0.248, -200.633],
[0.693, -0.473, 0.544, 73.403],
[0.596, -0.049, -0.802, -14.209],
[0, 0, 0, 1]])
},
{
pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows([
[-0.053, -0.077, 0.996, -45.633],
[-0.312, 0.949, 0.057, -12.255],
[-0.949, -0.307, -0.074, 53.562],
[0, 0, 0, 1]])
}
];
export function dynamicSuperpositionTest(plugin: PluginContext, src: string[], comp_id: string) {
return plugin.dataTransaction(async () => {
for (const s of src) {
await loadStructure(plugin, `https://www.ebi.ac.uk/pdbe/static/entry/${s}_updated.cif`, 'mmcif');
}
const pivot = MS.struct.filter.first([
MS.struct.generator.atomGroups({
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
})
]);
const rest = MS.struct.modifier.exceptBy({
0: MS.struct.modifier.includeSurroundings({
0: pivot,
radius: 5
}),
by: pivot
});
const query = compile<StructureSelection>(pivot);
const xs = plugin.managers.structure.hierarchy.current.structures;
const selections = xs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.cell.obj!.data))));
const transforms = superpose(selections);
await siteVisual(plugin, xs[0].cell, pivot, rest);
for (let i = 1; i < selections.length; i++) {
await transform(plugin, xs[i].cell, transforms[i - 1].bTransform);
await siteVisual(plugin, xs[i].cell, pivot, rest);
}
});
}
async function siteVisual(plugin: PluginContext, s: StateObjectRef<PSO.Molecule.Structure>, pivot: Expression, rest: Expression) {
const center = await plugin.builders.structure.tryCreateComponentFromExpression(s, pivot, 'pivot');
if (center) await plugin.builders.structure.representation.addRepresentation(center, { type: 'ball-and-stick', color: 'residue-name' });
const surr = await plugin.builders.structure.tryCreateComponentFromExpression(s, rest, 'rest');
if (surr) await plugin.builders.structure.representation.addRepresentation(surr, { type: 'ball-and-stick', color: 'uniform', size: 'uniform', sizeParams: { value: 0.33 } });
}
async function loadStructure(plugin: PluginContext, url: string, format: BuiltInTrajectoryFormat, assemblyId?: string) {
const data = await plugin.builders.data.download({ url: Asset.Url(url) });
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
const model = await plugin.builders.structure.createModel(trajectory);
const structure = await plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : void 0);
return { data, trajectory, model, structure };
}
function chainSelection(auth_asym_id: string) {
return MS.struct.generator.atomGroups({
'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), auth_asym_id])
});
}
function transform(plugin: PluginContext, s: StateObjectRef<PSO.Molecule.Structure>, matrix: Mat4) {
const b = plugin.state.data.build().to(s)
.insert(StateTransforms.Model.TransformStructureConformation, { transform: { name: 'matrix', params: { data: matrix, transpose: false } } });
return plugin.runTask(plugin.state.data.updateTree(b));
}

View File

@@ -1,119 +0,0 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Canvas3DProps } from '../../mol-canvas3d/canvas3d';
import { createPlugin } from '../../mol-plugin';
import { DefaultPluginSpec } from '../../mol-plugin/spec';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginContext } from '../../mol-plugin/context';
import './index.html';
import { Asset } from '../../mol-util/assets';
require('mol-plugin-ui/skin/light.scss');
type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: boolean, assemblyId?: string }
type _Preset = Pick<Canvas3DProps, 'multiSample' | 'postprocessing' | 'renderer'>
type Preset = { [K in keyof _Preset]: Partial<_Preset[K]> }
const Canvas3DPresets = {
illustrative: <Preset> {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusion: { name: 'on', params: { samples: 64, radius: 8, bias: 1.0, blurKernelSize: 13 } },
outline: { name: 'on', params: { scale: 1, threshold: 0.33 } }
},
renderer: {
ambientIntensity: 1,
lightIntensity: 0,
}
},
occlusion: <Preset> {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusion: { name: 'on', params: { samples: 64, radius: 8, bias: 1.0, blurKernelSize: 13 } },
outline: { name: 'off', params: { } }
},
renderer: {
ambientIntensity: 0.4,
lightIntensity: 0.6,
}
},
standard: <Preset> {
multiSample: {
mode: 'off' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusion: { name: 'off', params: { } },
outline: { name: 'off', params: { } }
},
renderer: {
ambientIntensity: 0.4,
lightIntensity: 0.6,
}
}
};
type Canvas3DPreset = keyof typeof Canvas3DPresets
class LightingDemo {
plugin: PluginContext;
init(target: string | HTMLElement) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginSpec(),
layout: {
initial: {
isExpanded: false,
showControls: false
},
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' }
}
});
this.setPreset('illustrative');
}
setPreset(preset: Canvas3DPreset) {
const props = Canvas3DPresets[preset];
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
...props,
multiSample: {
...this.plugin.canvas3d!.props.multiSample,
...props.multiSample
},
renderer: {
...this.plugin.canvas3d!.props.renderer,
...props.renderer
},
postprocessing: {
...this.plugin.canvas3d!.props.postprocessing,
...props.postprocessing
},
}});
}
async load({ url, format = 'mmcif', isBinary = false, assemblyId = '' }: LoadParams) {
await this.plugin.clear();
const data = await this.plugin.builders.data.download({ url: Asset.Url(url), isBinary }, { state: { isGhost: true } });
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
const model = await this.plugin.builders.structure.createModel(trajectory);
const structure = await this.plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : { name: 'model', params: { } });
const polymer = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'polymer');
if (polymer) await this.plugin.builders.structure.representation.addRepresentation(polymer, { type: 'spacefill', color: 'illustrative' });
const ligand = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'ligand');
if (ligand) await this.plugin.builders.structure.representation.addRepresentation(ligand, { type: 'ball-and-stick' });
}
}
(window as any).LightingDemo = new LightingDemo();

View File

@@ -1,15 +1,12 @@
/**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* 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 { CustomElementProperty } from '../../mol-model-props/common/custom-element-property';
import { Model, ElementIndex, ResidueIndex } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
import { CustomProperty } from '../../mol-model-props/common/custom-property';
import { Asset } from '../../mol-util/assets';
const EvolutionaryConservationPalette: Color[] = [
[255, 255, 129], // insufficient
@@ -26,14 +23,14 @@ const EvolutionaryConservationPalette: Color[] = [
const EvolutionaryConservationDefaultColor = Color(0x999999);
export const EvolutionaryConservation = CustomElementProperty.create<number>({
isStatic: true,
name: 'proteopedia-wrapper-evolutionary-conservation',
label: 'Evolutionary Conservation',
type: 'static',
async getData(model: Model, ctx: CustomProperty.Context) {
display: 'Evolutionary Conservation',
async getData(model: Model) {
const id = model.entryId.toLowerCase();
const url = Asset.getUrlAsset(ctx.assetManager, `https://proteopedia.org/cgi-bin/cnsrf?${id}`);
const json = await ctx.assetManager.resolve(url, 'json').runInContext(ctx.runtime);
const annotations = json.data?.residueAnnotations || [];
const req = await fetch(`https://proteopedia.org/cgi-bin/cnsrf?${id}`);
const json = await req.json();
const annotations = (json && json.residueAnnotations) || [];
const conservationMap = new Map<string, number>();
@@ -59,7 +56,7 @@ export const EvolutionaryConservation = CustomElementProperty.create<number>({
}
}
return { value: map, assets: [json] };
return map;
},
coloring: {
getColor(e: number) {
@@ -68,8 +65,8 @@ export const EvolutionaryConservation = CustomElementProperty.create<number>({
},
defaultColor: EvolutionaryConservationDefaultColor
},
getLabel(e) {
if (e === 10) return `Evolutionary Conservation: Insufficient Data`;
format(e) {
if (e === 10) return `Evolutionary Conservation: InsufficientData`;
return e ? `Evolutionary Conservation: ${e}` : void 0;
}
});

View File

@@ -6,63 +6,63 @@
*/
import { Unit, StructureProperties, StructureElement, Bond } from '../../mol-model/structure';
import { Unit, StructureProperties, StructureElement, Link } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
import { Location } from '../../mol-model/location';
import { ColorTheme, LocationColor } from '../../mol-theme/color';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { ParamDefinition as PD } from '../../mol-util/param-definition'
import { ThemeDataContext } from '../../mol-theme/theme';
import { Column } from '../../mol-data/db';
const Description = 'Gives every chain a color from a list based on its `asym_id` value.';
const Description = 'Gives every chain a color from a list based on its `asym_id` value.'
export function createProteopediaCustomTheme(colors: number[]) {
const ProteopediaCustomColorThemeParams = {
colors: PD.ObjectList({ color: PD.Color(Color(0xffffff)) }, ({ color }) => Color.toHexString(color),
{ defaultValue: colors.map(c => ({ color: Color(c) })) })
};
}
type ProteopediaCustomColorThemeParams = typeof ProteopediaCustomColorThemeParams
function getChainIdColorThemeParams(ctx: ThemeDataContext) {
return ProteopediaCustomColorThemeParams; // TODO return copy
return ProteopediaCustomColorThemeParams // TODO return copy
}
function getAsymId(unit: Unit): StructureElement.Property<string> {
switch (unit.kind) {
case Unit.Kind.Atomic:
return StructureProperties.chain.label_asym_id;
return StructureProperties.chain.label_asym_id
case Unit.Kind.Spheres:
case Unit.Kind.Gaussians:
return StructureProperties.coarse.asym_id;
return StructureProperties.coarse.asym_id
}
}
function addAsymIds(map: Map<string, number>, data: Column<string>) {
let j = map.size;
let j = map.size
for (let o = 0, ol = data.rowCount; o < ol; ++o) {
const k = data.value(o);
const k = data.value(o)
if (!map.has(k)) {
map.set(k, j);
j += 1;
map.set(k, j)
j += 1
}
}
}
function ProteopediaCustomColorTheme(ctx: ThemeDataContext, props: PD.Values<ProteopediaCustomColorThemeParams>): ColorTheme<ProteopediaCustomColorThemeParams> {
let color: LocationColor;
let color: LocationColor
const colors = props.colors, colorCount = colors.length, defaultColor = colors[0].color;
if (ctx.structure) {
const l = StructureElement.Location.create(ctx.structure);
const { models } = ctx.structure;
const asymIdSerialMap = new Map<string, number>();
const l = StructureElement.Location.create()
const { models } = ctx.structure
const asymIdSerialMap = new Map<string, number>()
for (let i = 0, il = models.length; i < il; ++i) {
const m = models[i];
addAsymIds(asymIdSerialMap, m.atomicHierarchy.chains.label_asym_id);
const m = models[i]
addAsymIds(asymIdSerialMap, m.atomicHierarchy.chains.label_asym_id)
if (m.coarseHierarchy.isDefined) {
addAsymIds(asymIdSerialMap, m.coarseHierarchy.spheres.asym_id);
addAsymIds(asymIdSerialMap, m.coarseHierarchy.gaussians.asym_id);
addAsymIds(asymIdSerialMap, m.coarseHierarchy.spheres.asym_id)
addAsymIds(asymIdSerialMap, m.coarseHierarchy.gaussians.asym_id)
}
}
@@ -71,17 +71,17 @@ export function createProteopediaCustomTheme(colors: number[]) {
const asym_id = getAsymId(location.unit);
const o = asymIdSerialMap.get(asym_id(location)) || 0;
return colors[o % colorCount].color;
} else if (Bond.isLocation(location)) {
const asym_id = getAsymId(location.aUnit);
l.unit = location.aUnit;
l.element = location.aUnit.elements[location.aIndex];
} else if (Link.isLocation(location)) {
const asym_id = getAsymId(location.aUnit)
l.unit = location.aUnit
l.element = location.aUnit.elements[location.aIndex]
const o = asymIdSerialMap.get(asym_id(l)) || 0;
return colors[o % colorCount].color;
}
return defaultColor;
};
return defaultColor
}
} else {
color = () => defaultColor;
color = () => defaultColor
}
return {
@@ -91,16 +91,16 @@ export function createProteopediaCustomTheme(colors: number[]) {
props,
description: Description,
legend: undefined
};
}
}
return {
name: 'proteopedia-custom',
const ProteopediaCustomColorThemeProvider: ColorTheme.Provider<ProteopediaCustomColorThemeParams> = {
label: 'Proteopedia Custom',
category: 'Custom',
factory: ProteopediaCustomColorTheme,
getParams: getChainIdColorThemeParams,
defaultValues: PD.getDefaultValues(ProteopediaCustomColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
};
}
return ProteopediaCustomColorThemeProvider;
}

View File

@@ -4,11 +4,11 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
import { Model, ResidueIndex } from '../../mol-model/structure';
import { ResidueIndex, Model } from '../../mol-model/structure';
import { BuiltInStructureRepresentationsName } from '../../mol-repr/structure/registry';
import { BuiltInColorThemeName } from '../../mol-theme/color';
import { AminoAcidNames } from '../../mol-model/structure/model/types';
import { PluginContext } from '../../mol-plugin/context';
import { StructureRepresentationRegistry } from '../../mol-repr/structure/registry';
import { ColorTheme } from '../../mol-theme/color';
export interface ModelInfo {
hetResidues: { name: string, indices: ResidueIndex[] }[],
@@ -53,12 +53,14 @@ export namespace ModelInfo {
const hetMap = new Map<string, ModelInfo['hetResidues'][0]>();
for (let rI = 0 as ResidueIndex; rI < residueCount; rI++) {
const comp_id = model.atomicHierarchy.residues.label_comp_id.value(rI);
if (AminoAcidNames.has(comp_id)) continue;
const mod_parent = model.properties.modifiedResidues.parentId.get(comp_id);
if (mod_parent && AminoAcidNames.has(mod_parent)) continue;
const cI = chainIndex[residueOffsets[rI]];
const eI = model.atomicHierarchy.index.getEntityFromChain(cI);
const entityType = model.entities.data.type.value(eI);
if (entityType !== 'non-polymer' && entityType !== 'branched') continue;
const comp_id = model.atomicHierarchy.atoms.label_comp_id.value(residueOffsets[rI]);
if (model.entities.data.type.value(eI) === 'water') continue;
let lig = hetMap.get(comp_id);
if (!lig) {
@@ -70,11 +72,10 @@ export namespace ModelInfo {
}
const preferredAssemblyId = await pref;
const symmetry = ModelSymmetry.Provider.get(model);
return {
hetResidues: hetResidues,
assemblies: symmetry ? symmetry.assemblies.map(a => ({ id: a.id, details: a.details, isPreferred: a.id === preferredAssemblyId })) : [],
assemblies: model.symmetry.assemblies.map(a => ({ id: a.id, details: a.details, isPreferred: a.id === preferredAssemblyId })),
preferredAssemblyId
};
}
@@ -84,7 +85,6 @@ export type SupportedFormats = 'cif' | 'pdb'
export interface LoadParams {
url: string,
format?: SupportedFormats,
isBinary?: boolean,
assemblyId?: string,
representationStyle?: RepresentationStyle
}
@@ -97,7 +97,7 @@ export interface RepresentationStyle {
}
export namespace RepresentationStyle {
export type Entry = { hide?: boolean, kind?: StructureRepresentationRegistry.BuiltIn, coloring?: ColorTheme.BuiltIn }
export type Entry = { hide?: boolean, kind?: BuiltInStructureRepresentationsName, coloring?: BuiltInColorThemeName }
}
export enum StateElements {

View File

@@ -48,7 +48,7 @@
width: 300px;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
<link rel="stylesheet" type="text/css" href="app.css" />
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
@@ -60,12 +60,11 @@
<option value='cif' selected>CIF</option>
<option value='pdb'>PDB</option>
</select>
<input type='checkbox' id='isBinary' style="display: inline-block; width: auto" /> <label for="isBinary"> Binary</label><br />
</div>
<div id="app"></div>
<div id="volume-streaming-wrapper"></div>
<script>
// it might be a good idea to define these colors in a separate script file
// it might be a good idea to define these colors in a separate script file
var CustomColors = [0x00ff00, 0x0000ff];
// create an instance of the plugin
@@ -74,28 +73,24 @@
console.log('Wrapper version', MolStarProteopediaWrapper.VERSION_MAJOR, MolStarProteopediaWrapper.VERSION_MINOR);
function $(id) { return document.getElementById(id); }
var pdbId = '1cbs', assemblyId= 'preferred', isBinary = true;
var url = 'https://www.ebi.ac.uk/pdbe/entry-files/download/' + pdbId + '.bcif'
var pdbId = '1cbs', assemblyId= 'preferred';
var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
var format = 'cif';
$('url').value = url;
$('url').onchange = function (e) { url = e.target.value; }
$('assemblyId').value = assemblyId;
$('assemblyId').onchange = function (e) { assemblyId = e.target.value; }
$('format').value = format;
$('format').onchange = function (e) { format = e.target.value; }
$('isBinary').checked = isBinary;
$('isBinary').onchange = function (e) { isBinary = !!e.target.checked; };
function loadAndSnapshot(params) {
PluginWrapper.load(params).then(() => {
setTimeout(() => snapshot = PluginWrapper.plugin.state.getSnapshot({ canvas3d: false /* do not save spinning state */ }), 500);
});
}
// var url = 'https://www.ebi.ac.uk/pdbe/entry-files/pdb' + pdbId + '.ent';
// var format = 'pdb';
// var assemblyId = 'deposited';
var representationStyle = {
// sequence: { coloring: 'proteopedia-custom' }, // or just { }
sequence: { coloring: 'proteopedia-custom' }, // or just { }
hetGroups: { kind: 'ball-and-stick' }, // or 'spacefill
water: { hide: true },
snfg3d: { hide: false }
@@ -105,7 +100,7 @@
customColorList: CustomColors
});
PluginWrapper.setBackground(0xffffff);
loadAndSnapshot({ url: url, format: format, isBinary: isBinary, assemblyId: assemblyId, representationStyle: representationStyle });
PluginWrapper.load({ url: url, format: format, assemblyId: assemblyId, representationStyle: representationStyle });
PluginWrapper.toggleSpin();
PluginWrapper.events.modelInfo.subscribe(function (info) {
@@ -113,8 +108,8 @@
listHetGroups(info);
});
addControl('Load Asym Unit', () => loadAndSnapshot({ url: url, format: format, isBinary }));
addControl('Load Assembly', () => loadAndSnapshot({ url: url, format: format, isBinary, assemblyId: assemblyId }));
addControl('Load Asym Unit', () => PluginWrapper.load({ url: url, format: format }));
addControl('Load Assembly', () => PluginWrapper.load({ url: url, format: format, assemblyId: assemblyId }));
addSeparator();
@@ -140,14 +135,14 @@
// Same as "wheel icon" and Viewport options
// addControl('Clip', () => PluginWrapper.viewport.setSettings({ clip: [33, 66] }));
// addControl('Reset Clip', () => PluginWrapper.viewport.setSettings({ clip: [1, 100] }));
addSeparator();
addHeader('Animation');
// adjust this number to make the animation faster or slower
// requires to "restart" the animation if changed
PluginWrapper.animate.modelIndex.targetFps = 30;
PluginWrapper.animate.modelIndex.maxFPS = 30;
addControl('Play To End', () => PluginWrapper.animate.modelIndex.onceForward());
addControl('Play To Start', () => PluginWrapper.animate.modelIndex.onceBackward());
@@ -173,24 +168,20 @@
addControl('Init', () => PluginWrapper.experimentalData.init($('volume-streaming-wrapper')));
addControl('Remove', () => PluginWrapper.experimentalData.remove());
addSeparator();
addSeparator();
addHeader('State');
var snapshot;
addControl('Set Snapshot', () => {
// const options = { data: true, behavior: false, animation: false, interactivity: false, canvas3d: false, camera: false, cameraTransition: false };
snapshot = PluginWrapper.plugin.state.getSnapshot(/** options */);
// console.log(JSON.stringify(snapshot, null, 2));
addControl('Create Snapshot', () => {
snapshot = PluginWrapper.snapshot.get();
// could use JSON.stringify(snapshot) and upload the data
});
addControl('Restore Snapshot', () => {
addControl('Apply Snapshot', () => {
if (!snapshot) return;
PluginWrapper.snapshot.set(snapshot);
});
addControl('Download State', () => {
PluginWrapper.snapshot.download('molj');
});
addControl('Download Session', () => {
PluginWrapper.snapshot.download('molx');
// or download snapshot using fetch or ajax or whatever
// or PluginWrapper.snapshot.download(url);
});
////////////////////////////////////////////////////////
@@ -226,7 +217,7 @@
var l = document.createElement('button');
l.innerText = r.name;
l.onclick = function () {
PluginWrapper.hetGroups.focusFirst(r.name, { doNotLabelWaters: true });
PluginWrapper.hetGroups.focusFirst(r.name);
};
div.appendChild(l);
});

View File

@@ -5,35 +5,38 @@
*/
import * as ReactDOM from 'react-dom';
import { Canvas3DProps, DefaultCanvas3DParams } from '../../mol-canvas3d/canvas3d';
import { createPlugin } from '../../mol-plugin';
import { DefaultPluginSpec } from '../../mol-plugin/spec';
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
import { PluginStateObject, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { CreateVolumeStreamingInfo, InitVolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
import { PluginCommands } from '../../mol-plugin/commands';
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
import './index.html'
import { PluginContext } from '../../mol-plugin/context';
import { PluginState } from '../../mol-plugin/state';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { StateBuilder, StateObject, StateSelection } from '../../mol-state';
import { Asset } from '../../mol-util/assets';
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 { ColorNames } from '../../mol-util/color/names';
import { getFormattedTime } from '../../mol-util/date';
import { download } from '../../mol-util/download';
import { RxEventHelper } from '../../mol-util/rx-event-helper';
import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin/state/objects';
import { AnimateModelIndex } from '../../mol-plugin/state/animation/built-in';
import { StateBuilder, StateObject, StateSelection } from '../../mol-state';
import { EvolutionaryConservation } from './annotation';
import { LoadParams, SupportedFormats, RepresentationStyle, ModelInfo, StateElements } from './helpers';
import { RxEventHelper } from '../../mol-util/rx-event-helper';
import { ControlsWrapper, volumeStreamingControls } from './ui/controls';
import { PluginState } from '../../mol-plugin/state';
import { Scheduler } from '../../mol-task';
import { createProteopediaCustomTheme } from './coloring';
import { LoadParams, ModelInfo, RepresentationStyle, StateElements, SupportedFormats } from './helpers';
import './index.html';
import { volumeStreamingControls } from './ui/controls';
require('../../mol-plugin-ui/skin/light.scss');
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { BuiltInStructureRepresentations } from '../../mol-repr/structure/registry';
import { BuiltInColorThemes } from '../../mol-theme/color';
import { BuiltInSizeThemes } from '../../mol-theme/size';
import { ColorNames } from '../../mol-util/color/names';
import { InitVolumeStreaming, CreateVolumeStreamingInfo } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
import { DefaultCanvas3DParams, Canvas3DProps } from '../../mol-canvas3d/canvas3d';
// import { Vec3 } from 'mol-math/linear-algebra';
// import { ParamDefinition } from 'mol-util/param-definition';
// import { Text } from 'mol-geo/geometry/text/text';
require('../../mol-plugin/skin/light.scss')
class MolStarProteopediaWrapper {
static VERSION_MAJOR = 5;
static VERSION_MINOR = 5;
static VERSION_MAJOR = 3;
static VERSION_MINOR = 4;
private _ev = RxEventHelper.create();
@@ -47,7 +50,7 @@ class MolStarProteopediaWrapper {
customColorList?: number[]
}) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginSpec(),
...DefaultPluginSpec,
animations: [
AnimateModelIndex
],
@@ -55,27 +58,27 @@ class MolStarProteopediaWrapper {
initial: {
isExpanded: false,
showControls: false
},
controls: {
right: ControlsWrapper
}
},
components: {
remoteState: 'none'
}
});
const customColoring = createProteopediaCustomTheme((options && options.customColorList) || []);
this.plugin.representation.structure.themes.colorThemeRegistry.add(customColoring);
this.plugin.representation.structure.themes.colorThemeRegistry.add(EvolutionaryConservation.colorThemeProvider!);
this.plugin.managers.lociLabels.addProvider(EvolutionaryConservation.labelProvider!);
this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider, true);
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add('proteopedia-custom', customColoring);
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(EvolutionaryConservation.Descriptor.name, EvolutionaryConservation.colorTheme!);
this.plugin.lociLabels.addProvider(EvolutionaryConservation.labelProvider);
this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider);
}
get state() {
return this.plugin.state.data;
return this.plugin.state.dataState;
}
private download(b: StateBuilder.To<PSO.Root>, url: string, isBinary: boolean) {
return b.apply(StateTransforms.Data.Download, { url: Asset.Url(url), isBinary });
private download(b: StateBuilder.To<PSO.Root>, url: string) {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
}
private model(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats) {
@@ -89,18 +92,10 @@ class MolStarProteopediaWrapper {
private structure(assemblyId: string) {
const model = this.state.build().to(StateElements.Model);
const props = {
type: assemblyId ? {
name: 'assembly' as const,
params: { id: assemblyId }
} : {
name: 'model' as const,
params: { }
}
};
const s = model
.apply(StateTransforms.Model.StructureFromModel, props, { ref: StateElements.Assembly });
.apply(StateTransforms.Model.CustomModelProperties, { properties: [EvolutionaryConservation.Descriptor.name] }, { ref: StateElements.ModelProps, state: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: StateElements.Assembly });
s.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: StateElements.Sequence });
s.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' }, { ref: StateElements.Het });
@@ -123,10 +118,9 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.SequenceVisual);
} else {
root.applyOrUpdate(StateElements.SequenceVisual, StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(this.plugin, structure, {
type: (style.sequence && style.sequence.kind) || 'cartoon',
color: (style.sequence && style.sequence.coloring) || 'unit-index'
}));
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
(style.sequence && style.sequence.kind) || 'cartoon',
(style.sequence && style.sequence.coloring) || 'unit-index', structure));
}
}
@@ -139,10 +133,9 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.HetVisual);
} else {
root.applyOrUpdate(StateElements.HetVisual, StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(this.plugin, structure, {
type: (style.hetGroups && style.hetGroups.kind) || 'ball-and-stick',
color: style.hetGroups && style.hetGroups.coloring
}));
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
(style.hetGroups && style.hetGroups.kind) || 'ball-and-stick',
(style.hetGroups && style.hetGroups.coloring), structure));
}
}
}
@@ -156,7 +149,7 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.Het3DSNFG);
} else {
root.applyOrUpdate(StateElements.Het3DSNFG, StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(this.plugin, structure, { type: 'carbohydrate' }));
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin, 'carbohydrate', void 0, structure));
}
}
}
@@ -167,11 +160,9 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.WaterVisual);
} else {
root.applyOrUpdate(StateElements.WaterVisual, StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(this.plugin, structure, {
type: (style.water && style.water.kind) || 'ball-and-stick',
typeParams: { alpha: 0.51 },
color: style.water && style.water.coloring
}));
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
(style.water && style.water.kind) || 'ball-and-stick',
(style.water && style.water.coloring), structure, { alpha: 0.51 }));
}
}
@@ -189,21 +180,20 @@ class MolStarProteopediaWrapper {
const model = this.getObj<PluginStateObject.Molecule.Model>('model');
if (!model) return;
const info = await ModelInfo.get(this.plugin, model, checkPreferredAssembly);
const info = await ModelInfo.get(this.plugin, model, checkPreferredAssembly)
this.events.modelInfo.next(info);
return info;
}
private applyState(tree: StateBuilder) {
return PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
return PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
}
private emptyLoadedParams: LoadParams = { url: '', format: 'cif', isBinary: false, assemblyId: '' };
private loadedParams: LoadParams = { url: '', format: 'cif', isBinary: false, assemblyId: '' };
async load({ url, format = 'cif', assemblyId = '', isBinary = false, representationStyle }: LoadParams) {
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
async load({ url, format = 'cif', assemblyId = 'deposited', representationStyle }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.data;
const state = this.plugin.state.dataState;
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
loadType = 'full';
@@ -212,8 +202,8 @@ class MolStarProteopediaWrapper {
}
if (loadType === 'full') {
await PluginCommands.State.RemoveObject(this.plugin, { state, ref: state.tree.root.ref });
const modelTree = this.model(this.download(state.build().toRoot(), url, isBinary), format);
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
const modelTree = this.model(this.download(state.build().toRoot(), url), format);
await this.applyState(modelTree);
const info = await this.doInfo(true);
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
@@ -223,45 +213,37 @@ class MolStarProteopediaWrapper {
const tree = state.build();
const info = await this.doInfo(true);
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
const props = {
type: assemblyId ? {
name: 'assembly' as const,
params: { id: asmId }
} : {
name: 'model' as const,
params: { }
}
};
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: asmId }));
await this.applyState(tree);
}
await this.updateStyle(representationStyle);
this.loadedParams = { url, format, assemblyId };
Scheduler.setImmediate(() => PluginCommands.Camera.Reset.dispatch(this.plugin, { }));
}
async updateStyle(style?: RepresentationStyle, partial?: boolean) {
const tree = this.visual(style, partial);
if (!tree) return;
await PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
}
setBackground(color: number) {
if (!this.plugin.canvas3d) return;
const renderer = this.plugin.canvas3d.props.renderer;
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
}
toggleSpin() {
if (!this.plugin.canvas3d) return;
const trackball = this.plugin.canvas3d.props.trackball;
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
const spinning = trackball.spin;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
}
viewport = {
setSettings: (settings?: Canvas3DProps) => {
PluginCommands.Canvas3D.SetSettings(this.plugin, {
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, {
settings: settings || DefaultCanvas3DParams
});
}
@@ -269,21 +251,36 @@ class MolStarProteopediaWrapper {
camera = {
toggleSpin: () => this.toggleSpin(),
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, { })
}
resetPosition: () => PluginCommands.Camera.Reset.dispatch(this.plugin, { }),
// setClip: (options?: { distance?: number, near?: number, far?: number }) => {
// if (!options) {
// PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, {
// settings: {
// cameraClipDistance: DefaultCanvas3DParams.cameraClipDistance,
// clip: DefaultCanvas3DParams.clip
// }
// });
// return;
// }
private animateModelIndexTargetFps() {
return Math.max(1, this.animate.modelIndex.targetFps | 0);
// options = options || { };
// const props = this.plugin.canvas3d.props;
// const clipNear = typeof options.near === 'undefined' ? props.clip[0] : options.near;
// const clipFar = typeof options.far === 'undefined' ? props.clip[1] : options.far;
// PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, {
// settings: { cameraClipDistance: options.distance, clip: [clipNear, clipFar] }
// });
// }
}
animate = {
modelIndex: {
targetFps: 8,
onceForward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'forward' } } }); },
onceBackward: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'once', params: { direction: 'backward' } } }); },
palindrome: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'palindrome', params: {} } }); },
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: {} } }); },
stop: () => this.plugin.managers.animation.stop()
maxFPS: 8,
onceForward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'forward' } } }) },
onceBackward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'backward' } } }) },
palindrome: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'palindrome', params: {} } }) },
loop: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'loop', params: {} } }) },
stop: () => this.plugin.state.animation.stop()
}
}
@@ -294,8 +291,13 @@ class MolStarProteopediaWrapper {
}
const state = this.state;
// const visuals = state.selectQ(q => q.ofType(PluginStateObject.Molecule.Structure.Representation3D).filter(c => c.transform.transformer === StateTransforms.Representation.StructureRepresentation3D));
// for (const v of visuals) {
// }
const tree = state.build();
const colorTheme = { name: EvolutionaryConservation.propertyProvider.descriptor.name, params: this.plugin.representation.structure.themes.colorThemeRegistry.get(EvolutionaryConservation.propertyProvider.descriptor.name).defaultValues };
const colorTheme = { name: EvolutionaryConservation.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(EvolutionaryConservation.Descriptor.name).defaultValues };
if (!params || !!params.sequence) {
tree.to(StateElements.SequenceVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
@@ -304,7 +306,7 @@ class MolStarProteopediaWrapper {
tree.to(StateElements.HetVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
}
await PluginCommands.State.Update(this.plugin, { state, tree });
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
}
}
@@ -324,7 +326,7 @@ class MolStarProteopediaWrapper {
remove: () => {
const r = this.state.select(StateSelection.Generators.ofTransformer(CreateVolumeStreamingInfo))[0];
if (!r) return;
PluginCommands.State.RemoveObject(this.plugin, { state: this.state, ref: r.transform.ref });
PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.state, ref: r.transform.ref });
if (this.experimentalDataElement) {
ReactDOM.unmountComponentAtNode(this.experimentalDataElement);
this.experimentalDataElement = void 0;
@@ -335,12 +337,14 @@ class MolStarProteopediaWrapper {
hetGroups = {
reset: () => {
const update = this.state.build().delete(StateElements.HetGroupFocusGroup);
PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
PluginCommands.Camera.Reset(this.plugin, { });
PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
},
focusFirst: async (compId: string, options?: { hideLabels: boolean, doNotLabelWaters: boolean }) => {
focusFirst: async (compId: string) => {
if (!this.state.transforms.has(StateElements.Assembly)) return;
await PluginCommands.Camera.Reset(this.plugin, { });
await PluginCommands.Camera.Reset.dispatch(this.plugin, { });
// const asm = (this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure).data;
const update = this.state.build();
@@ -355,66 +359,65 @@ class MolStarProteopediaWrapper {
const surroundings = MS.struct.modifier.includeSurroundings({ 0: core, radius: 5, 'as-whole-residues': true });
const group = update.to(StateElements.Assembly).group(StateTransforms.Misc.CreateGroup, { label: compId }, { ref: StateElements.HetGroupFocusGroup });
const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
const coreSel = group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Core', expression: core }, { ref: StateElements.HetGroupFocus });
coreSel.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
type: 'ball-and-stick'
}));
coreSel.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
type: 'label',
typeParams: { level: 'element' }
}), { tags: ['proteopedia-labels'] });
group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Core', expression: core }, { ref: StateElements.HetGroupFocus })
.apply(StateTransforms.Representation.StructureRepresentation3D, this.createCoreVisualParams());
group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Surroundings', expression: surroundings })
.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
type: 'ball-and-stick',
color: 'uniform', colorParams: { value: ColorNames.gray },
size: 'uniform', sizeParams: { value: 0.33 }
}));
.apply(StateTransforms.Representation.StructureRepresentation3D, this.createSurVisualParams());
// sel.apply(StateTransforms.Representation.StructureLabels3D, {
// target: { name: 'residues', params: { } },
// options: {
// ...ParamDefinition.getDefaultValues(Text.Params),
// background: true,
// backgroundMargin: 0.2,
// backgroundColor: ColorNames.snow,
// backgroundOpacity: 0.9,
// }
// });
if (!options?.hideLabels) {
// Labels
const waters = MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.entityType(), 'water']),
});
const exclude = options?.doNotLabelWaters ? MS.struct.combinator.merge([core, waters]) : core;
const onlySurroundings = MS.struct.modifier.exceptBy({ 0: surroundings, by: exclude });
group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Surroundings (only)', expression: onlySurroundings })
.apply(StateTransforms.Representation.StructureRepresentation3D, createStructureRepresentationParams(this.plugin, asm.data, {
type: 'label',
typeParams: { level: 'residue' }
}), { tags: ['proteopedia-labels'] }); // the tag can later be used to toggle the labels
}
await PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
const focus = (this.state.select(StateElements.HetGroupFocus)[0].obj as PluginStateObject.Molecule.Structure).data;
const sphere = focus.boundary.sphere;
const radius = Math.max(sphere.radius, 5);
const snapshot = this.plugin.canvas3d!.camera.getFocus(sphere.center, radius);
PluginCommands.Camera.SetSnapshot(this.plugin, { snapshot, durationMs: 250 });
// const asmCenter = asm.boundary.sphere.center;
// const position = Vec3.sub(Vec3.zero(), sphere.center, asmCenter);
// Vec3.normalize(position, position);
// Vec3.scaleAndAdd(position, sphere.center, position, sphere.radius);
const snapshot = this.plugin.canvas3d.camera.getFocus(sphere.center, Math.max(sphere.radius, 5));
PluginCommands.Camera.SetSnapshot.dispatch(this.plugin, { snapshot, durationMs: 250 });
}
}
private createSurVisualParams() {
const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, {
repr: BuiltInStructureRepresentations['ball-and-stick'],
color: [BuiltInColorThemes.uniform, () => ({ value: ColorNames.gray })],
size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )]
});
}
private createCoreVisualParams() {
const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, {
repr: BuiltInStructureRepresentations['ball-and-stick'],
// color: [BuiltInColorThemes.uniform, () => ({ value: ColorNames.gray })],
// size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )]
});
}
snapshot = {
get: (params?: PluginState.SnapshotParams) => {
return this.plugin.state.getSnapshot(params);
get: () => {
return this.plugin.state.getSnapshot();
},
set: (snapshot: PluginState.Snapshot) => {
return this.plugin.state.setSnapshot(snapshot);
},
download: async (type: 'molj' | 'molx' = 'molj', params?: PluginState.SnapshotParams) => {
const data = await this.plugin.managers.snapshot.serialize({ type, params });
download(data, `mol-star_state_${getFormattedTime()}.${type}`);
},
fetch: async (url: string, type: 'molj' | 'molx' = 'molj') => {
download: async (url: string) => {
try {
const data = await this.plugin.runTask(this.plugin.fetch({ url, type: 'binary' }));
this.loadedParams = { ...this.emptyLoadedParams };
return await this.plugin.managers.snapshot.open(new File([data], `state.${type}`));
const data = await this.plugin.runTask(this.plugin.fetch({ url }));
const snapshot = JSON.parse(data);
await this.plugin.state.setSnapshot(snapshot);
} catch (e) {
console.log(e);
}

View File

@@ -6,13 +6,27 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { PluginContextContainer } from '../../../mol-plugin-ui/plugin';
import { TransformUpdaterControl } from '../../../mol-plugin-ui/state/update-transform';
import { PluginUIComponent } from '../../../mol-plugin/ui/base';
import { CurrentObject, PluginContextContainer } from '../../../mol-plugin/ui/plugin';
import { AnimationControls } from '../../../mol-plugin/ui/state/animation';
import { CameraSnapshots } from '../../../mol-plugin/ui/camera';
import { PluginContext } from '../../../mol-plugin/context';
import { TransformUpdaterControl } from '../../../mol-plugin/ui/state/update-transform';
import { StateElements } from '../helpers';
export class ControlsWrapper extends PluginUIComponent {
render() {
return <div className='msp-scrollable-container msp-right-controls'>
<CurrentObject />
<AnimationControls />
<CameraSnapshots />
</div>;
}
}
export function volumeStreamingControls(plugin: PluginContext, parent: Element) {
ReactDOM.render(<PluginContextContainer plugin={plugin}>
<TransformUpdaterControl nodeRef={StateElements.VolumeStreaming} />
</PluginContextContainer>, parent);
<TransformUpdaterControl nodeRef={StateElements.VolumeStreaming} />
</PluginContextContainer>,
parent);
}

View File

@@ -4,7 +4,7 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Task, Progress, Scheduler, MultistepTask, chunkedSubtask } from '../mol-task';
import { Task, Progress, Scheduler, MultistepTask, chunkedSubtask } from '../mol-task'
import { now } from '../mol-util/now';
export async function test1() {
@@ -85,19 +85,19 @@ export const ms = MultistepTask('ms-task', ['step 1', 'step 2', 'step 3'], async
await step(0);
const child = Task.create('chunked', async ctx => {
const s = await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 125 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p));
const s = await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 125 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p))
return s.i;
});
await child.runAsChild(ctx);
await Scheduler.delay(250);
await step(1);
await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 80 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p));
await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 80 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p))
await Scheduler.delay(250);
await step(2);
await Scheduler.delay(250);
return p.i + 3;
});
})
export function abortingObserver(p: Progress) {

View File

@@ -1,214 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Box3D } from '../../../mol-math/geometry';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { RuntimeContext } from '../../../mol-task';
import { sphericalCollocation } from '../collocation';
import { Basis, CubeGridInfo } from '../data-model';
describe('alpha-orbitals-cubes', () => {
it('water', async () => {
const grid: CubeGridInfo = {
params: {
basis: _testBasis,
cutoffThreshold: 0,
sphericalOrder: 'cca-reverse',
boxExpand: 0,
gridSpacing: []
},
box: Box3D.create(Vec3.create(-1, -1, -1), Vec3.create(1, 1, 1)),
delta: Vec3.create(2, 2, 2),
dimensions: Vec3.create(2, 2, 2),
npoints: 8,
size: Vec3.create(2, 2, 2)
};
const matrix = await sphericalCollocation(grid, {
energy: 0,
occupancy: 0,
alpha: [-2.2623991420609075e-16, 0.6360205395000592, 0.6672122399886391, -0.3876927909355508, -1.6780131293332933e-16, 2.844782862661151e-16, 4.977960694176068e-19, -2.3945919908996803e-16]
}, RuntimeContext.Synchronous);
const expected = [-0.1451730622877498, 0.06479453956039086, -0.2777738736440713, -0.057116584776260436, 0.05929916178822645, 0.2742903371231049, -0.07221698722165386, 0.15389180241391376];
expect(matrix.length).toBe(expected.length);
for (let i = 0; i < matrix.length; i++) {
expect(Math.abs(matrix[i] - expected[i]) < 1e-6).toBe(true);
}
});
});
const _testBasis: Basis = {
'atoms': [
{
'center': [
0.025886090588624934,
0.019164790004065606,
-0.013539970104105408
] as Vec3,
'shells': [
{
'angularMomentum': [0],
'coefficients': [
[
-0.004151277818987536,
-0.02067024147993795,
-0.05150303336984537,
0.33462711739899537,
0.5621061300983125,
0.17129946969948573
]
],
'exponents': [
152.28769660788095,
27.928015215973073,
7.848374792384515,
1.1223350202705642,
0.5093846587907856,
0.24292266532510307
]
},
{
'angularMomentum': [1],
'coefficients': [
[
0.007924233646294425,
0.051441048251911314,
0.18984000600705359,
0.4049863191150474,
0.40123628611490797,
0.1051855189039082
]
],
'exponents': [
27.203421487167727,
7.09409912597673,
2.5383362605345954,
1.0610730767843852,
0.4851948916410433,
0.22938302550642545
]
}
]
},
{
'center': [
0.5082729578468134,
1.6880351220025265,
0.4963443067810461
] as Vec3,
'shells': [
{
'angularMomentum': [0],
'coefficients': [
[
0.009163596280542963,
0.04936149294292479,
0.16853830490998634,
0.37056279972195677,
0.4164915298246781,
0.13033408410772263
]
],
'exponents': [
33.710073211949485,
6.180705022740464,
1.7291385346152253,
0.5940057549921978,
0.2306698170449518,
0.09500256906284119
]
},
{
'angularMomentum': [0],
'coefficients': [
[
-0.32279868167000036,
3.209629817295221,
2.4672629224617935,
-0.048487066612842224,
-0.2611850111200143,
-0.8917817597810863,
-1.9607480081275706,
-2.203769342520311,
-0.6896328935259993
]
],
'exponents': [
10.256286070314905,
0.6227965325875392,
0.2391007667853915,
33.710073211949485,
6.180705022740464,
1.7291385346152253,
0.5940057549921978,
0.2306698170449518,
0.09500256906284119
]
}
]
},
{
'center': [
1.1367367844436005,
-0.47018519422670163,
-1.356802622574504
] as Vec3,
'shells': [
{
'angularMomentum': [0],
'coefficients': [
[
0.009163596280542963,
0.04936149294292479,
0.16853830490998634,
0.37056279972195677,
0.4164915298246781,
0.13033408410772263
]
],
'exponents': [
33.710073211949485,
6.180705022740464,
1.7291385346152253,
0.5940057549921978,
0.2306698170449518,
0.09500256906284119
]
},
{
'angularMomentum': [0],
'coefficients': [
[
-0.32279868167000036,
3.209629817295221,
2.4672629224617935,
-0.048487066612842224,
-0.2611850111200143,
-0.8917817597810863,
-1.9607480081275706,
-2.203769342520311,
-0.6896328935259993
]
],
'exponents': [
10.256286070314905,
0.6227965325875392,
0.2391007667853915,
33.710073211949485,
6.180705022740464,
1.7291385346152253,
0.5940057549921978,
0.2306698170449518,
0.09500256906284119
]
}
]
}
]
};

View File

@@ -1,162 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Inspired by https://github.com/dgasmith/gau2grid.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Vec3 } from '../../mol-math/linear-algebra';
import { RuntimeContext } from '../../mol-task';
import { arrayMin } from '../../mol-util/array';
import { AlphaOrbital, CubeGridInfo } from './data-model';
import { normalizeBasicOrder, SphericalFunctions } from './spherical-functions';
export async function sphericalCollocation(
grid: CubeGridInfo,
orbital: AlphaOrbital,
taskCtx: RuntimeContext
) {
const { basis, sphericalOrder, cutoffThreshold } = grid.params;
let baseCount = 0;
for (const atom of basis.atoms) {
for (const shell of atom.shells) {
for (const L of shell.angularMomentum) {
if (L > 4) {
// TODO: will L > 4 be required? Would need to precompute more functions in that case.
throw new Error('Angular momentum L > 4 not supported.');
}
baseCount += 2 * L + 1;
}
}
}
const matrix = new Float32Array(grid.npoints);
let baseIndex = 0;
for (const atom of basis.atoms) {
for (const shell of atom.shells) {
let amIndex = 0;
for (const L of shell.angularMomentum) {
const alpha = normalizeBasicOrder(
L,
orbital.alpha.slice(baseIndex, baseIndex + 2 * L + 1),
sphericalOrder
);
baseIndex += 2 * L + 1;
collocationBasis(
matrix,
grid,
L,
shell.coefficients[amIndex++],
shell.exponents,
atom.center,
cutoffThreshold,
alpha
);
if (taskCtx.shouldUpdate) {
await taskCtx.update({
message: 'Computing...',
current: baseIndex,
max: baseCount,
isIndeterminate: false,
});
}
}
}
}
return matrix;
}
function collocationBasis(
matrix: Float32Array,
grid: CubeGridInfo,
L: number,
coefficients: number[],
exponents: number[],
center: Vec3,
cutoffThreshold: number,
alpha: number[]
) {
const ncoeff = exponents.length;
const sphericalFunc = SphericalFunctions[L];
const cx = center[0],
cy = center[1],
cz = center[2];
const ny = grid.dimensions[1],
nz = grid.dimensions[2];
const gdx = grid.delta[0],
gdy = grid.delta[1],
gdz = grid.delta[2];
const sx = grid.box.min[0],
sy = grid.box.min[1],
sz = grid.box.min[2];
const cutoffRadius =
cutoffThreshold > 0
? Math.sqrt(-Math.log(cutoffThreshold) / arrayMin(exponents))
: 10000;
const cutoffSquared = cutoffRadius * cutoffRadius;
const radiusBox = getRadiusBox(grid, center, cutoffRadius);
const iMin = radiusBox[0][0],
jMin = radiusBox[0][1],
kMin = radiusBox[0][2];
const iMax = radiusBox[1][0],
jMax = radiusBox[1][1],
kMax = radiusBox[1][2];
for (let i = iMin; i <= iMax; i++) {
const x = sx + gdx * i - cx;
const oX = i * ny * nz;
for (let j = jMin; j <= jMax; j++) {
const y = sy + gdy * j - cy;
const oY = oX + j * nz;
for (let k = kMin; k <= kMax; k++) {
const z = sz + gdz * k - cz;
const R2 = x * x + y * y + z * z;
if (R2 > cutoffSquared) {
continue;
}
let gaussianSum = 0;
for (let c = 0; c < ncoeff; c++) {
gaussianSum +=
coefficients[c] * Math.exp(-exponents[c] * R2);
}
const sphericalSum = L === 0 ? alpha[0] : sphericalFunc(alpha, x, y, z);
matrix[k + oY] += gaussianSum * sphericalSum;
}
}
}
}
function getRadiusBox(grid: CubeGridInfo, center: Vec3, radius: number) {
const r = Vec3.create(radius, radius, radius);
const min = Vec3.scaleAndAdd(Vec3(), center, r, -1);
const max = Vec3.add(Vec3(), center, r);
Vec3.sub(min, min, grid.box.min);
Vec3.sub(max, max, grid.box.min);
Vec3.div(min, min, grid.delta);
Vec3.floor(min, min);
Vec3.max(min, min, Vec3());
Vec3.div(max, max, grid.delta);
Vec3.ceil(max, max);
Vec3.min(max, max, Vec3.subScalar(Vec3(), grid.dimensions, 1));
return [min, max];
}

View File

@@ -1,131 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Mat4, Tensor, Vec3 } from '../../mol-math/linear-algebra';
import { Grid } from '../../mol-model/volume';
import { SphericalBasisOrder } from './spherical-functions';
import { Box3D, RegularGrid3d } from '../../mol-math/geometry';
import { arrayMin, arrayMax, arrayRms, arrayMean } from '../../mol-util/array';
// Note: generally contracted gaussians are currently not supported.
export interface SphericalElectronShell {
exponents: number[];
angularMomentum: number[];
// number[] for each angular momentum
coefficients: number[][];
}
export interface Basis {
atoms: {
// in Bohr units!
center: Vec3;
shells: SphericalElectronShell[];
}[];
}
export interface AlphaOrbital {
energy: number;
occupancy: number;
alpha: number[];
}
export interface CubeGridComputationParams {
basis: Basis;
/**
* for each electron shell compute a cutoff radius as
* const cutoffRadius = Math.sqrt(-Math.log(cutoffThreshold) / arrayMin(exponents));
*/
cutoffThreshold: number;
sphericalOrder: SphericalBasisOrder;
boxExpand: number;
gridSpacing: number | [atomCountThreshold: number, spacing: number][];
doNotComputeIsovalues?: boolean;
}
export interface CubeGridInfo {
params: CubeGridComputationParams;
dimensions: Vec3;
box: Box3D;
size: Vec3;
npoints: number;
delta: Vec3;
}
export interface CubeGrid {
grid: Grid;
isovalues?: { negative?: number; positive?: number };
}
export function initCubeGrid(params: CubeGridComputationParams): CubeGridInfo {
const geometry = params.basis.atoms.map(a => a.center);
const { gridSpacing: spacing, boxExpand: expand } = params;
const count = geometry.length;
const box = Box3D.expand(
Box3D(),
Box3D.fromVec3Array(Box3D(), geometry),
Vec3.create(expand, expand, expand)
);
const size = Box3D.size(Vec3(), box);
const spacingThresholds =
typeof spacing === 'number' ? [[0, spacing]] : [...spacing];
spacingThresholds.sort((a, b) => b[0] - a[0]);
let s = 0.4;
for (let i = 0; i <= spacingThresholds.length; i++) {
s = spacingThresholds[i][1];
if (spacingThresholds[i][0] <= count) break;
}
const dimensions = Vec3.ceil(Vec3(), Vec3.scale(Vec3(), size, 1 / s));
return {
params,
box,
dimensions,
size,
npoints: dimensions[0] * dimensions[1] * dimensions[2],
delta: Vec3.div(Vec3(), size, Vec3.subScalar(Vec3(), dimensions, 1)),
};
}
const BohrToAngstromFactor = 0.529177210859;
export function createGrid(gridInfo: RegularGrid3d, values: Float32Array, axisOrder: number[]) {
const boxSize = Box3D.size(Vec3(), gridInfo.box);
const boxOrigin = Vec3.clone(gridInfo.box.min);
Vec3.scale(boxSize, boxSize, BohrToAngstromFactor);
Vec3.scale(boxOrigin, boxOrigin, BohrToAngstromFactor);
const scale = Mat4.fromScaling(
Mat4(),
Vec3.div(
Vec3(),
boxSize,
Vec3.sub(Vec3(), gridInfo.dimensions, Vec3.create(1, 1, 1))
)
);
const translate = Mat4.fromTranslation(Mat4(), boxOrigin);
const matrix = Mat4.mul(Mat4(), translate, scale);
const grid: Grid = {
transform: { kind: 'matrix', matrix },
cells: Tensor.create(
Tensor.Space(gridInfo.dimensions, axisOrder, Float32Array),
(values as any) as Tensor.Data
),
stats: {
min: arrayMin(values),
max: arrayMax(values),
mean: arrayMean(values),
sigma: arrayRms(values),
},
};
return grid;
}

View File

@@ -1,124 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsDensityGridValues } from './gpu/compute';
export function createSphericalCollocationDensityGrid(
params: CubeGridComputationParams, orbitals: AlphaOrbital[], webgl?: WebGLContext
): Task<CubeGrid> {
return Task.create('Spherical Collocation Grid', async (ctx) => {
const cubeGrid = initCubeGrid(params);
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl!, cubeGrid, orbitals);
// console.timeEnd('gpu');
} else {
throw new Error('Missing OES_texture_float WebGL extension.');
}
const grid = createGrid(cubeGrid, matrix, [0, 1, 2]);
let isovalues: { negative?: number, positive?: number } | undefined;
if (!params.doNotComputeIsovalues) {
isovalues = computeDensityIsocontourValues(matrix, 0.85);
}
return { grid, isovalues };
});
}
export function computeDensityIsocontourValues(input: Float32Array, cumulativeThreshold: number) {
let weightSum = 0;
for (let i = 0, _i = input.length; i < _i; i++) {
const v = input[i];
const w = Math.abs(v);
weightSum += w;
}
const avgWeight = weightSum / input.length;
let minWeight = 3 * avgWeight;
// do not try to identify isovalues for degenerate data
// e.g. all values are almost same
if (Math.abs(avgWeight - input[0] * input[0]) < 1e-5) {
return { negative: void 0, positive: void 0 };
}
let size = 0;
while (true) {
let csum = 0;
size = 0;
for (let i = 0, _i = input.length; i < _i; i++) {
const v = input[i];
const w = Math.abs(v);
if (w >= minWeight) {
csum += w;
size++;
}
}
if (csum / weightSum > cumulativeThreshold) {
break;
}
minWeight -= avgWeight;
}
const values = new Float32Array(size);
const weights = new Float32Array(size);
const indices = new Int32Array(size);
let o = 0;
for (let i = 0, _i = input.length; i < _i; i++) {
const v = input[i];
const w = Math.abs(v);
if (w >= minWeight) {
values[o] = v;
weights[o] = w;
indices[o] = o;
o++;
}
}
sortArray(
indices,
(indices, i, j) => weights[indices[j]] - weights[indices[i]]
);
let cweight = 0,
cutoffIndex = 0;
for (let i = 0; i < size; i++) {
cweight += weights[indices[i]];
if (cweight / weightSum >= cumulativeThreshold) {
cutoffIndex = i;
break;
}
}
let positive = Number.POSITIVE_INFINITY,
negative = Number.NEGATIVE_INFINITY;
for (let i = 0; i < cutoffIndex; i++) {
const v = values[indices[i]];
if (v > 0) {
if (v < positive) positive = v;
} else if (v < 0) {
if (v > negative) negative = v;
}
}
return {
negative: negative !== Number.NEGATIVE_INFINITY ? negative : void 0,
positive: positive !== Number.POSITIVE_INFINITY ? positive : void 0,
};
}

View File

@@ -1,170 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { createGrid3dComputeRenderable } from '../../../mol-gl/compute/grid3d';
import { TextureSpec, UnboxedValues, UniformSpec } from '../../../mol-gl/renderable/schema';
import { WebGLContext } from '../../../mol-gl/webgl/context';
import { RuntimeContext } from '../../../mol-task';
import { ValueCell } from '../../../mol-util';
import { arrayMin } from '../../../mol-util/array';
import { AlphaOrbital, Basis, CubeGridInfo } from '../data-model';
import { normalizeBasicOrder, SphericalBasisOrder } from '../spherical-functions';
import { MAIN, UTILS } from './shader.frag';
const Schema = {
tCenters: TextureSpec('image-float32', 'rgba', 'float', 'nearest'),
tInfo: TextureSpec('image-float32', 'rgba', 'float', 'nearest'),
tCoeff: TextureSpec('image-float32', 'rgb', 'float', 'nearest'),
tAlpha: TextureSpec('image-float32', 'alpha', 'float', 'nearest'),
uNCenters: UniformSpec('i'),
uNAlpha: UniformSpec('i'),
uNCoeff: UniformSpec('i'),
uMaxCoeffs: UniformSpec('i'),
};
const Orbitals = createGrid3dComputeRenderable({
schema: Schema,
loopBounds: ['uNCenters', 'uMaxCoeffs'],
mainCode: MAIN,
utilCode: UTILS,
returnCode: 'v',
values(params: { grid: CubeGridInfo, orbital: AlphaOrbital }) {
return createTextureData(params.grid, params.orbital);
}
});
const Density = createGrid3dComputeRenderable({
schema: {
...Schema,
uOccupancy: UniformSpec('f'),
},
loopBounds: ['uNCenters', 'uMaxCoeffs'],
mainCode: MAIN,
utilCode: UTILS,
returnCode: 'current + uOccupancy * v * v',
values(params: { grid: CubeGridInfo, orbitals: AlphaOrbital[] }) {
return {
...createTextureData(params.grid, params.orbitals[0]),
uOccupancy: 0
};
},
cumulative: {
states(params: { grid: CubeGridInfo, orbitals: AlphaOrbital[] }) {
return params.orbitals.filter(o => o.occupancy !== 0);
},
update({ grid }, state: AlphaOrbital, values) {
const alpha = getNormalizedAlpha(grid.params.basis, state.alpha, grid.params.sphericalOrder);
ValueCell.updateIfChanged(values.uOccupancy, state.occupancy);
ValueCell.update(values.tAlpha, { width: alpha.length, height: 1, array: alpha });
}
}
});
export function gpuComputeAlphaOrbitalsGridValues(ctx: RuntimeContext, webgl: WebGLContext, grid: CubeGridInfo, orbital: AlphaOrbital) {
return Orbitals(ctx, webgl, grid, { grid, orbital });
}
export function gpuComputeAlphaOrbitalsDensityGridValues(ctx: RuntimeContext, webgl: WebGLContext, grid: CubeGridInfo, orbitals: AlphaOrbital[]) {
return Density(ctx, webgl, grid, { grid, orbitals });
}
function getNormalizedAlpha(basis: Basis, alphaOrbitals: number[], sphericalOrder: SphericalBasisOrder) {
const alpha = new Float32Array(alphaOrbitals.length);
let aO = 0;
for (const atom of basis.atoms) {
for (const shell of atom.shells) {
for (const L of shell.angularMomentum) {
const a0 = normalizeBasicOrder(L, alphaOrbitals.slice(aO, aO + 2 * L + 1), sphericalOrder);
for (let i = 0; i < a0.length; i++) alpha[aO + i] = a0[i];
aO += 2 * L + 1;
}
}
}
return alpha;
}
function createTextureData(grid: CubeGridInfo, orbital: AlphaOrbital): UnboxedValues<typeof Schema> {
const { basis, sphericalOrder, cutoffThreshold } = grid.params;
let centerCount = 0;
let baseCount = 0;
let coeffCount = 0;
for (const atom of basis.atoms) {
for (const shell of atom.shells) {
for (const L of shell.angularMomentum) {
if (L > 4) {
// TODO: will L > 4 be required? Would need to precompute more functions in that case.
throw new Error('Angular momentum L > 4 not supported.');
}
centerCount++;
baseCount += 2 * L + 1;
coeffCount += shell.exponents.length;
}
}
}
const centers = new Float32Array(4 * centerCount);
// L, alpha_offset, coeff_offset_start, coeff_offset_end
const info = new Float32Array(4 * centerCount);
const alpha = new Float32Array(baseCount);
const coeff = new Float32Array(3 * coeffCount);
let maxCoeffs = 0;
let cO = 0, aO = 0, coeffO = 0;
for (const atom of basis.atoms) {
for (const shell of atom.shells) {
let amIndex = 0;
for (const L of shell.angularMomentum) {
const a0 = normalizeBasicOrder(L, orbital.alpha.slice(aO, aO + 2 * L + 1), sphericalOrder);
const cutoffRadius = cutoffThreshold > 0
? Math.sqrt(-Math.log(cutoffThreshold) / arrayMin(shell.exponents))
: 10000;
centers[4 * cO + 0] = atom.center[0];
centers[4 * cO + 1] = atom.center[1];
centers[4 * cO + 2] = atom.center[2];
centers[4 * cO + 3] = cutoffRadius * cutoffRadius;
info[4 * cO + 0] = L;
info[4 * cO + 1] = aO;
info[4 * cO + 2] = coeffO;
info[4 * cO + 3] = coeffO + shell.exponents.length;
for (let i = 0; i < a0.length; i++) alpha[aO + i] = a0[i];
const c0 = shell.coefficients[amIndex++];
for (let i = 0; i < shell.exponents.length; i++) {
coeff[3 * (coeffO + i) + 0] = c0[i];
coeff[3 * (coeffO + i) + 1] = shell.exponents[i];
}
if (c0.length > maxCoeffs) {
maxCoeffs = c0.length;
}
cO++;
aO += 2 * L + 1;
coeffO += shell.exponents.length;
}
}
}
return {
uNCenters: centerCount,
uNAlpha: baseCount,
uNCoeff: coeffCount,
uMaxCoeffs: maxCoeffs,
tCenters: { width: centerCount, height: 1, array: centers },
tInfo: { width: centerCount, height: 1, array: info },
tCoeff: { width: coeffCount, height: 1, array: coeff },
tAlpha: { width: baseCount, height: 1, array: alpha },
};
}

View File

@@ -1,145 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
export const UTILS = `
float L1(vec3 p, float a0, float a1, float a2) {
return a0 * p.z + a1 * p.x + a2 * p.y;
}
float L2(vec3 p, float a0, float a1, float a2, float a3, float a4) {
float x = p.x, y = p.y, z = p.z;
float xx = x * x, yy = y * y, zz = z * z;
return (
a0 * (-0.5 * xx - 0.5 * yy + zz) +
a1 * (1.7320508075688772 * x * z) +
a2 * (1.7320508075688772 * y * z) +
a3 * (0.8660254037844386 * xx - 0.8660254037844386 * yy) +
a4 * (1.7320508075688772 * x * y)
);
}
float L3(vec3 p, float a0, float a1, float a2, float a3, float a4, float a5, float a6) {
float x = p.x, y = p.y, z = p.z;
float xx = x * x, yy = y * y, zz = z * z;
float xxx = xx * x, yyy = yy * y, zzz = zz * z;
return (
a0 * (-1.5 * xx * z - 1.5 * yy * z + zzz) +
a1 * (-0.6123724356957945 * xxx - 0.6123724356957945 * x * yy + 2.449489742783178 * x * zz) +
a2 * (-0.6123724356957945 * xx * y - 0.6123724356957945 * yyy + 2.449489742783178 * y * zz) +
a3 * (1.9364916731037085 * xx * z - 1.9364916731037085 * yy * z) +
a4 * (3.872983346207417 * x * y * z) +
a5 * (0.7905694150420949 * xxx - 2.3717082451262845 * x * yy) +
a6 * (2.3717082451262845 * xx * y - 0.7905694150420949 * yyy)
);
}
float L4(vec3 p, float a0, float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8) {
float x = p.x, y = p.y, z = p.z;
float xx = x * x, yy = y * y, zz = z * z;
float xxx = xx * x, yyy = yy * y, zzz = zz * z;
float xxxx = xxx * x, yyyy = yyy * y, zzzz = zzz * z;
return (
a0 * (0.375 * xxxx + 0.75 * xx * yy + 0.375 * yyyy - 3.0 * xx * zz - 3.0 * yy * zz + zzzz) +
a1 * (-2.3717082451262845 * xxx * z - 2.3717082451262845 * x * yy * z + 3.1622776601683795 * x * zzz) +
a2 * (-2.3717082451262845 * xx * y * z - 2.3717082451262845 * yyy * z + 3.1622776601683795 * y * zzz) +
a3 * (-0.5590169943749475 * xxxx + 0.5590169943749475 * yyyy + 3.3541019662496847 * xx * zz - 3.3541019662496847 * yy * zz) +
a4 * (-1.118033988749895 * xxx * y - 1.118033988749895 * x * yyy + 6.708203932499369 * x * y * zz) +
a5 * (2.091650066335189 * xxx * z + -6.274950199005566 * x * yy * z) +
a6 * (6.274950199005566 * xx * y * z + -2.091650066335189 * yyy * z) +
a7 * (0.739509972887452 * xxxx - 4.437059837324712 * xx * yy + 0.739509972887452 * yyyy) +
a8 * (2.958039891549808 * xxx * y + -2.958039891549808 * x * yyy)
);
}
float alpha(float offset, float f) {
#ifdef WEBGL1
// in webgl1, the value is in the alpha channel!
return texture2D(tAlpha, vec2(offset * f, 0.5)).a;
#else
return texture2D(tAlpha, vec2(offset * f, 0.5)).x;
#endif
}
float Y(int L, vec3 X, float aO, float fA) {
if (L == 0) {
return alpha(aO, fA);
} else if (L == 1) {
return L1(X,
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA)
);
} else if (L == 2) {
return L2(X,
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA)
);
} else if (L == 3) {
return L3(X,
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA),
alpha(aO + 5.0, fA), alpha(aO + 6.0, fA)
);
} else if (L == 4) {
return L4(X,
alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA),
alpha(aO + 5.0, fA), alpha(aO + 6.0, fA), alpha(aO + 7.0, fA), alpha(aO + 8.0, fA)
);
}
// TODO: do we need L > 4?
return 0.0;
}
#ifndef WEBGL1
float R(float R2, int start, int end, float fCoeff) {
float gauss = 0.0;
for (int i = start; i < end; i++) {
vec2 c = texture2D(tCoeff, vec2(float(i) * fCoeff, 0.5)).xy;
gauss += c.x * exp(-c.y * R2);
}
return gauss;
}
#else
float R(float R2, int start, int end, float fCoeff) {
float gauss = 0.0;
int o = start;
for (int i = 0; i < uMaxCoeffs; i++) {
if (o >= end) break;
vec2 c = texture2D(tCoeff, vec2(float(o) * fCoeff, 0.5)).xy;
gauss += c.x * exp(-c.y * R2);
o++;
}
return gauss;
}
#endif
`;
export const MAIN = `
float fCenter = 1.0 / float(uNCenters - 1);
float fCoeff = 1.0 / float(uNCoeff - 1);
float fA = 1.0 / float(uNAlpha - 1);
float v = 0.0;
for (int i = 0; i < uNCenters; i++) {
vec2 cCoord = vec2(float(i) * fCenter, 0.5);
vec4 center = texture2D(tCenters, cCoord);
vec3 X = xyz - center.xyz;
float R2 = dot(X, X);
// center.w is squared cutoff radius
if (R2 > center.w) {
continue;
}
vec4 info = texture2D(tInfo, cCoord);
int L = int(info.x);
float aO = info.y;
int coeffStart = int(info.z);
int coeffEnd = int(info.w);
v += R(R2, coeffStart, coeffEnd, fCoeff) * Y(L, X, aO, fA);
}
`;

View File

@@ -1,131 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Inspired by https://github.com/dgasmith/gau2grid.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { sphericalCollocation } from './collocation';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsGridValues } from './gpu/compute';
// setDebugMode(true);
export function createSphericalCollocationGrid(
params: CubeGridComputationParams, orbital: AlphaOrbital, webgl?: WebGLContext
): Task<CubeGrid> {
return Task.create('Spherical Collocation Grid', async (ctx) => {
const cubeGrid = initCubeGrid(params);
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl!, cubeGrid, orbital);
// console.timeEnd('gpu');
} else {
// console.time('cpu');
matrix = await sphericalCollocation(cubeGrid, orbital, ctx);
// console.timeEnd('cpu');
}
const grid = createGrid(cubeGrid, matrix, [0, 1, 2]);
let isovalues: { negative?: number, positive?: number } | undefined;
if (!params.doNotComputeIsovalues) {
isovalues = computeOrbitalIsocontourValues(matrix, 0.85);
}
return { grid, isovalues };
});
}
export function computeOrbitalIsocontourValues(input: Float32Array, cumulativeThreshold: number) {
let weightSum = 0;
for (let i = 0, _i = input.length; i < _i; i++) {
const v = input[i];
const w = v * v;
weightSum += w;
}
const avgWeight = weightSum / input.length;
let minWeight = 3 * avgWeight;
// do not try to identify isovalues for degenerate data
// e.g. all values are almost same
if (Math.abs(avgWeight - input[0] * input[0]) < 1e-5) {
return { negative: void 0, positive: void 0 };
}
let size = 0;
while (true) {
let csum = 0;
size = 0;
for (let i = 0, _i = input.length; i < _i; i++) {
const v = input[i];
const w = v * v;
if (w >= minWeight) {
csum += w;
size++;
}
}
if (csum / weightSum > cumulativeThreshold) {
break;
}
minWeight -= avgWeight;
}
const values = new Float32Array(size);
const weights = new Float32Array(size);
const indices = new Int32Array(size);
let o = 0;
for (let i = 0, _i = input.length; i < _i; i++) {
const v = input[i];
const w = v * v;
if (w >= minWeight) {
values[o] = v;
weights[o] = w;
indices[o] = o;
o++;
}
}
sortArray(
indices,
(indices, i, j) => weights[indices[j]] - weights[indices[i]]
);
let cweight = 0,
cutoffIndex = 0;
for (let i = 0; i < size; i++) {
cweight += weights[indices[i]];
if (cweight / weightSum >= cumulativeThreshold) {
cutoffIndex = i;
break;
}
}
let positive = Number.POSITIVE_INFINITY,
negative = Number.NEGATIVE_INFINITY;
for (let i = 0; i < cutoffIndex; i++) {
const v = values[indices[i]];
if (v > 0) {
if (v < positive) positive = v;
} else if (v < 0) {
if (v > negative) negative = v;
}
}
return {
negative: negative !== Number.NEGATIVE_INFINITY ? negative : void 0,
positive: positive !== Number.POSITIVE_INFINITY ? positive : void 0,
};
}

View File

@@ -1,93 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Inspired by https://github.com/dgasmith/gau2grid.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
// gaussian:
// R_0, R^+_1, R^-_1, ..., R^+_l, R^-_l
// cca:
// R^-_(l), R^-_(l-1), ..., R_0, ..., R^+_(l-1), R^+_l
// cca-reverse:
// R^+_(l), R^+_(l-1), ..., R_0, ..., R^-_(l-1), R^-_l
export type SphericalBasisOrder = 'gaussian' | 'cca' | 'cca-reverse';
export function normalizeBasicOrder(
L: number,
alpha: number[],
order: SphericalBasisOrder
) {
if (order === 'gaussian' || L === 0) return alpha;
const ret: number[] = [alpha[L]];
for (let l = 0; l < L; l++) {
const a = alpha[L - l - 1],
b = alpha[L + l + 1];
if (order === 'cca') ret.push(b, a);
else ret.push(a, b);
}
return ret;
}
export type SphericalFunc = (
alpha: number[],
x: number,
y: number,
z: number
) => number;
export const SphericalFunctions: SphericalFunc[] = [L0, L1, L2, L3, L4];
// L_i functions were auto-generated.
function L0(alpha: number[], x: number, y: number, z: number) {
return alpha[0];
}
function L1(alpha: number[], x: number, y: number, z: number) {
return alpha[0] * z + alpha[1] * x + alpha[2] * y;
}
function L2(alpha: number[], x: number, y: number, z: number) {
const xx = x * x, yy = y * y, zz = z * z;
return (
alpha[0] * (-0.5 * xx - 0.5 * yy + zz) +
alpha[1] * (1.7320508075688772 * x * z) +
alpha[2] * (1.7320508075688772 * y * z) +
alpha[3] * (0.8660254037844386 * xx - 0.8660254037844386 * yy) +
alpha[4] * (1.7320508075688772 * x * y)
);
}
function L3(alpha: number[], x: number, y: number, z: number) {
const xx = x * x, yy = y * y, zz = z * z;
const xxx = xx * x, yyy = yy * y, zzz = zz * z;
return (
alpha[0] * (-1.5 * xx * z - 1.5 * yy * z + zzz) +
alpha[1] * (-0.6123724356957945 * xxx - 0.6123724356957945 * x * yy + 2.449489742783178 * x * zz) +
alpha[2] * (-0.6123724356957945 * xx * y - 0.6123724356957945 * yyy + 2.449489742783178 * y * zz) +
alpha[3] * (1.9364916731037085 * xx * z - 1.9364916731037085 * yy * z) +
alpha[4] * (3.872983346207417 * x * y * z) +
alpha[5] * (0.7905694150420949 * xxx - 2.3717082451262845 * x * yy) +
alpha[6] * (2.3717082451262845 * xx * y - 0.7905694150420949 * yyy)
);
}
function L4(alpha: number[], x: number, y: number, z: number) {
const xx = x * x, yy = y * y, zz = z * z;
const xxx = xx * x, yyy = yy * y, zzz = zz * z;
const xxxx = xxx * x, yyyy = yyy * y, zzzz = zzz * z;
return (
alpha[0] * (0.375 * xxxx + 0.75 * xx * yy + 0.375 * yyyy - 3.0 * xx * zz - 3.0 * yy * zz + zzzz) +
alpha[1] * (-2.3717082451262845 * xxx * z - 2.3717082451262845 * x * yy * z + 3.1622776601683795 * x * zzz) +
alpha[2] * (-2.3717082451262845 * xx * y * z - 2.3717082451262845 * yyy * z + 3.1622776601683795 * y * zzz) +
alpha[3] * (-0.5590169943749475 * xxxx + 0.5590169943749475 * yyyy + 3.3541019662496847 * xx * zz - 3.3541019662496847 * yy * zz) +
alpha[4] * (-1.118033988749895 * xxx * y - 1.118033988749895 * x * yyy + 6.708203932499369 * x * y * zz) +
alpha[5] * (2.091650066335189 * xxx * z + -6.274950199005566 * x * yy * z) +
alpha[6] * (6.274950199005566 * xx * y * z + -2.091650066335189 * yyy * z) +
alpha[7] * (0.739509972887452 * xxxx - 4.437059837324712 * xx * yy + 0.739509972887452 * yyyy) +
alpha[8] * (2.958039891549808 * xxx * y + -2.958039891549808 * x * yyy)
);
}

View File

@@ -1,236 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { PluginStateObject, PluginStateTransform } from '../../mol-plugin-state/objects';
import { createSphericalCollocationGrid } from './orbitals';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Task } from '../../mol-task';
import { CustomProperties } from '../../mol-model/custom-property';
import { SphericalBasisOrder } from './spherical-functions';
import { Volume } from '../../mol-model/volume';
import { PluginContext } from '../../mol-plugin/context';
import { ColorNames } from '../../mol-util/color/names';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { StateTransformer } from '../../mol-state';
import { Theme } from '../../mol-theme/theme';
import { VolumeRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation';
import { AlphaOrbital, Basis, CubeGrid } from './data-model';
import { createSphericalCollocationDensityGrid } from './density';
import { Tensor } from '../../mol-math/linear-algebra';
export class BasisAndOrbitals extends PluginStateObject.Create<{ basis: Basis, order: SphericalBasisOrder, orbitals: AlphaOrbital[] }>({ name: 'Basis', typeClass: 'Object' }) { }
export const StaticBasisAndOrbitals = PluginStateTransform.BuiltIn({
name: 'static-basis-and-orbitals',
display: 'Basis and Orbitals',
from: PluginStateObject.Root,
to: BasisAndOrbitals,
params: {
label: PD.Text('Orbital Data', { isHidden: true }),
basis: PD.Value<Basis>(void 0 as any, { isHidden: true }),
order: PD.Text<SphericalBasisOrder>('gaussian' as SphericalBasisOrder, { isHidden: true }),
orbitals: PD.Value<AlphaOrbital[]>([], { isHidden: true })
},
})({
apply({ params }) {
return new BasisAndOrbitals({ basis: params.basis, order: params.order, orbitals: params.orbitals }, { label: params.label });
}
});
const CreateOrbitalVolumeParamBase = {
cutoffThreshold: PD.Numeric(0.0015, { min: 0, max: 0.1, step: 0.0001 }),
boxExpand: PD.Numeric(4.5, { min: 0, max: 7, step: 0.1 }),
gridSpacing: PD.ObjectList({ atomCount: PD.Numeric(0), spacing: PD.Numeric(0.35, { min: 0.1, max: 2, step: 0.01 }) }, e => `Atoms ${e.atomCount}: ${e.spacing}`, {
defaultValue: [
{ atomCount: 55, spacing: 0.5 },
{ atomCount: 40, spacing: 0.45 },
{ atomCount: 25, spacing: 0.4 },
{ atomCount: 0, spacing: 0.35 },
]
}),
clampValues: PD.MappedStatic('off', {
off: PD.EmptyGroup(),
on: PD.Group({
sigma: PD.Numeric(8, { min: 1, max: 20 }, { description: 'Clamp values to range [sigma * negIsoValue, sigma * posIsoValue].' })
})
})
};
function clampData(matrix: Tensor.Data, min: number, max: number) {
for (let i = 0, _i = matrix.length; i < _i; i++) {
const v = matrix[i];
if (v < min) matrix[i] = min;
else if (v > max) matrix[i] = max;
}
}
function clampGrid(data: CubeGrid, v: number) {
const grid = data.grid;
const min = (data.isovalues?.negative ?? data.grid.stats.min) * v;
const max = (data.isovalues?.positive ?? data.grid.stats.max) * v;
// clamp values for better direct volume resolution
// current implementation uses Byte array for values
// if this is not enough, update mol* to use float
// textures instead
if (grid.stats.min < min || grid.stats.max > max) {
clampData(data.grid.cells.data, min, max);
if (grid.stats.min < min) {
(grid.stats.min as number) = min;
}
if (grid.stats.max > max) {
(grid.stats.max as number) = max;
}
}
}
export const CreateOrbitalVolume = PluginStateTransform.BuiltIn({
name: 'create-orbital-volume',
display: 'Orbital Volume',
from: BasisAndOrbitals,
to: PluginStateObject.Volume.Data,
params: (a) => {
if (!a) {
return { index: PD.Numeric(0), ...CreateOrbitalVolumeParamBase };
}
return {
index: PD.Select(0, a.data.orbitals.map((o, i) => [i, `[${i + 1}] ${o.energy.toFixed(4)}`])),
...CreateOrbitalVolumeParamBase
};
}
})({
apply({ a, params }, plugin: PluginContext) {
return Task.create('Orbital Volume', async ctx => {
const data = await createSphericalCollocationGrid({
basis: a.data.basis,
cutoffThreshold: params.cutoffThreshold,
sphericalOrder: a.data.order,
boxExpand: params.boxExpand,
gridSpacing: params.gridSpacing.map(e => [e.atomCount, e.spacing] as [number, number])
}, a.data.orbitals[params.index], plugin.canvas3d?.webgl).runInContext(ctx);
const volume: Volume = {
grid: data.grid,
sourceData: { name: 'custom grid', kind: 'alpha-orbitals', data },
customProperties: new CustomProperties(),
_propertyData: Object.create(null),
};
if (params.clampValues?.name === 'on') {
clampGrid(data, params.clampValues?.params?.sigma ?? 8);
}
return new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' });
});
}
});
export const CreateOrbitalDensityVolume = PluginStateTransform.BuiltIn({
name: 'create-orbital-density-volume',
display: 'Orbital Density Volume',
from: BasisAndOrbitals,
to: PluginStateObject.Volume.Data,
params: CreateOrbitalVolumeParamBase
})({
apply({ a, params }, plugin: PluginContext) {
return Task.create('Orbital Volume', async ctx => {
const data = await createSphericalCollocationDensityGrid({
basis: a.data.basis,
cutoffThreshold: params.cutoffThreshold,
sphericalOrder: a.data.order,
boxExpand: params.boxExpand,
gridSpacing: params.gridSpacing.map(e => [e.atomCount, e.spacing] as [number, number])
}, a.data.orbitals, plugin.canvas3d?.webgl).runInContext(ctx);
const volume: Volume = {
grid: data.grid,
sourceData: { name: 'custom grid', kind: 'alpha-orbitals', data },
customProperties: new CustomProperties(),
_propertyData: Object.create(null),
};
if (params.clampValues?.name === 'on') {
clampGrid(data, params.clampValues?.params?.sigma ?? 8);
}
return new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' });
});
}
});
export const CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
name: 'create-orbital-representation-3d',
display: 'Orbital Representation 3D',
from: PluginStateObject.Volume.Data,
to: PluginStateObject.Volume.Representation3D,
params: {
directVolume: PD.Boolean(false),
relativeIsovalue: PD.Numeric(1, { min: 0.01, max: 5, step: 0.01 }),
kind: PD.Select<'positive' | 'negative'>('positive', [['positive', 'Positive'], ['negative', 'Negative']]),
color: PD.Color(ColorNames.blue),
alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
xrayShaded: PD.Boolean(false),
pickable: PD.Boolean(true)
}
})({
canAutoUpdate() {
return true;
},
apply({ a, params: srcParams }, plugin: PluginContext) {
return Task.create('Orbitals Representation 3D', async ctx => {
const params = volumeParams(plugin, a, srcParams);
const propertyCtx = { runtime: ctx, assetManager: plugin.managers.asset };
const provider = plugin.representation.volume.registry.get(params.type.name);
if (provider.ensureCustomProperties) await provider.ensureCustomProperties.attach(propertyCtx, a.data);
const props = params.type.params || {};
const repr = provider.factory({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.volume.themes }, provider.getParams);
repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data }, params));
await repr.createOrUpdate(props, a.data).runInContext(ctx);
repr.setState({ pickable: srcParams.pickable });
return new PluginStateObject.Volume.Representation3D({ repr, source: a }, { label: provider.label, description: VolumeRepresentation3DHelpers.getDescription(props) });
});
},
update({ a, b, newParams: srcParams }, plugin: PluginContext) {
return Task.create('Orbitals Representation 3D', async ctx => {
const newParams = volumeParams(plugin, a, srcParams);
const props = { ...b.data.repr.props, ...newParams.type.params };
b.data.repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data }, newParams));
await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
b.data.repr.setState({ pickable: srcParams.pickable });
b.description = VolumeRepresentation3DHelpers.getDescription(props);
return StateTransformer.UpdateResult.Updated;
});
}
});
function volumeParams(plugin: PluginContext, volume: PluginStateObject.Volume.Data, params: StateTransformer.Params<typeof CreateOrbitalRepresentation3D>) {
if (volume.data.sourceData.kind !== 'alpha-orbitals') throw new Error('Invalid data source kind.');
const { isovalues } = volume.data.sourceData.data as CubeGrid;
if (!isovalues) throw new Error('Isovalues are not computed.');
const value = isovalues[params.kind];
return createVolumeRepresentationParams(plugin, volume.data, params.directVolume ? {
type: 'direct-volume',
typeParams: {
alpha: params.alpha,
renderMode: {
name: 'isosurface',
params: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, singleLayer: false }
},
xrayShaded: params.xrayShaded
},
color: 'uniform',
colorParams: { value: params.color }
} : {
type: 'isosurface',
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded },
color: 'uniform',
colorParams: { value: params.color }
});
}

View File

@@ -1,370 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Structure, StructureElement, StructureProperties } from '../../mol-model/structure';
import { Task, RuntimeContext } from '../../mol-task';
import { CentroidHelper } from '../../mol-math/geometry/centroid-helper';
import { AccessibleSurfaceAreaProvider } from '../../mol-model-props/computed/accessible-surface-area';
import { Vec3 } from '../../mol-math/linear-algebra';
import { getElementMoleculeType } from '../../mol-model/structure/util';
import { MoleculeType } from '../../mol-model/structure/model/types';
import { AccessibleSurfaceArea } from '../../mol-model-props/computed/accessible-surface-area/shrake-rupley';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { MembraneOrientation } from './prop';
interface ANVILContext {
structure: Structure,
numberOfSpherePoints: number,
stepSize: number,
minThickness: number,
maxThickness: number,
asaCutoff: number,
offsets: ArrayLike<number>,
exposed: ArrayLike<boolean>,
centroid: Vec3,
extent: number
};
export const ANVILParams = {
numberOfSpherePoints: PD.Numeric(120, { min: 35, max: 700, step: 1 }, { description: 'Number of spheres/directions to test for membrane placement. Original value is 350.' }),
stepSize: PD.Numeric(1, { min: 0.25, max: 4, step: 0.25 }, { description: 'Thickness of membrane slices that will be tested' }),
minThickness: PD.Numeric(20, { min: 10, max: 30, step: 1}, { description: 'Minimum membrane thickness used during refinement' }),
maxThickness: PD.Numeric(40, { min: 30, max: 50, step: 1}, { description: 'Maximum membrane thickness used during refinement' }),
asaCutoff: PD.Numeric(40, { min: 10, max: 100, step: 1 }, { description: 'Absolute ASA cutoff above which residues will be considered' })
};
export type ANVILParams = typeof ANVILParams
export type ANVILProps = PD.Values<ANVILParams>
/**
* Implements:
* Membrane positioning for high- and low-resolution protein structures through a binary classification approach
* Guillaume Postic, Yassine Ghouzam, Vincent Guiraud, and Jean-Christophe Gelly
* Protein Engineering, Design & Selection, 2015, 15
* doi: 10.1093/protein/gzv063
*/
export function computeANVIL(structure: Structure, props: ANVILProps) {
return Task.create('Compute Membrane Orientation', async runtime => {
return await calculate(runtime, structure, props);
});
}
const centroidHelper = new CentroidHelper();
function initialize(structure: Structure, props: ANVILProps): ANVILContext {
const l = StructureElement.Location.create(structure);
const { label_atom_id, x, y, z } = StructureProperties.atom;
const elementCount = structure.polymerResidueCount;
centroidHelper.reset();
let offsets = new Int32Array(elementCount);
let exposed = new Array<boolean>(elementCount);
const accessibleSurfaceArea = structure && AccessibleSurfaceAreaProvider.get(structure);
const asa = accessibleSurfaceArea.value!;
const vec = Vec3();
let m = 0;
for (let i = 0, il = structure.units.length; i < il; ++i) {
const unit = structure.units[i];
const { elements } = unit;
l.unit = unit;
for (let j = 0, jl = elements.length; j < jl; ++j) {
const eI = elements[j];
l.element = eI;
// consider only amino acids
if (getElementMoleculeType(unit, eI) !== MoleculeType.Protein) {
continue;
}
// only CA is considered for downstream operations
if (label_atom_id(l) !== 'CA') {
continue;
}
// while iterating use first pass to compute centroid
Vec3.set(vec, x(l), y(l), z(l));
centroidHelper.includeStep(vec);
// keep track of offsets and exposed state to reuse
offsets[m] = structure.serialMapping.getSerialIndex(l.unit, l.element);
exposed[m] = AccessibleSurfaceArea.getValue(l, asa) > props.asaCutoff;
m++;
}
}
// omit potentially empty tail1
offsets = offsets.slice(0, m);
exposed = exposed.slice(0, m);
// calculate centroid and extent
centroidHelper.finishedIncludeStep();
const centroid = centroidHelper.center;
for (let k = 0, kl = offsets.length; k < kl; k++) {
setLocation(l, structure, offsets[k]);
Vec3.set(vec, x(l), y(l), z(l));
centroidHelper.radiusStep(vec);
}
const extent = 1.2 * Math.sqrt(centroidHelper.radiusSq);
return {
...props,
structure: structure,
offsets: offsets,
exposed: exposed,
centroid: centroid,
extent: extent
};
}
export async function calculate(runtime: RuntimeContext, structure: Structure, params: ANVILProps): Promise<MembraneOrientation> {
const { label_comp_id } = StructureProperties.atom;
const ctx = initialize(structure, params);
const initialHphobHphil = HphobHphil.filtered(ctx, label_comp_id);
const initialMembrane = findMembrane(ctx, generateSpherePoints(ctx, ctx.numberOfSpherePoints), initialHphobHphil, label_comp_id);
const alternativeMembrane = findMembrane(ctx, findProximateAxes(ctx, initialMembrane), initialHphobHphil, label_comp_id);
const membrane = initialMembrane.qmax! > alternativeMembrane.qmax! ? initialMembrane : alternativeMembrane;
return {
planePoint1: membrane.planePoint1,
planePoint2: membrane.planePoint2,
normalVector: membrane.normalVector!,
radius: ctx.extent,
centroid: ctx.centroid
};
}
interface MembraneCandidate {
planePoint1: Vec3,
planePoint2: Vec3,
stats: HphobHphil,
normalVector?: Vec3,
spherePoint?: Vec3,
qmax?: number
}
namespace MembraneCandidate {
export function initial(c1: Vec3, c2: Vec3, stats: HphobHphil): MembraneCandidate {
return {
planePoint1: c1,
planePoint2: c2,
stats: stats
};
}
export function scored(spherePoint: Vec3, c1: Vec3, c2: Vec3, stats: HphobHphil, qmax: number, centroid: Vec3): MembraneCandidate {
const diam_vect = Vec3();
Vec3.sub(diam_vect, centroid, spherePoint);
return {
planePoint1: c1,
planePoint2: c2,
stats: stats,
normalVector: diam_vect,
spherePoint: spherePoint,
qmax: qmax
};
}
}
function findMembrane(ctx: ANVILContext, spherePoints: Vec3[], initialStats: HphobHphil, label_comp_id: StructureElement.Property<string>): MembraneCandidate {
const { centroid, stepSize, minThickness, maxThickness } = ctx;
// best performing membrane
let membrane: MembraneCandidate;
// score of the best performing membrane
let qmax = 0;
// construct slices of thickness 1.0 along the axis connecting the centroid and the spherePoint
const diam = Vec3();
for (let i = 0, il = spherePoints.length; i < il; i++) {
const spherePoint = spherePoints[i];
Vec3.sub(diam, centroid, spherePoint);
Vec3.scale(diam, diam, 2);
const diamNorm = Vec3.magnitude(diam);
const qvartemp = [];
for (let i = 0, il = diamNorm - stepSize; i < il; i += stepSize) {
const c1 = Vec3();
const c2 = Vec3();
Vec3.scaleAndAdd(c1, spherePoint, diam, i / diamNorm);
Vec3.scaleAndAdd(c2, spherePoint, diam, (i + stepSize) / diamNorm);
// evaluate how well this membrane slice embeddeds the peculiar residues
const stats = HphobHphil.filtered(ctx, label_comp_id, (testPoint: Vec3) => isInMembranePlane(testPoint, diam, c1, c2));
qvartemp.push(MembraneCandidate.initial(c1, c2, stats));
}
let jmax = (minThickness / stepSize) - 1;
for (let width = 0, widthl = maxThickness; width < widthl;) {
const imax = qvartemp.length - 1 - jmax;
for (let i = 0, il = imax; i < il; i++) {
const c1 = qvartemp[i].planePoint1;
const c2 = qvartemp[i + jmax].planePoint2;
let hphob = 0;
let hphil = 0;
let total = 0;
for (let j = 0; j < jmax; j++) {
const ij = qvartemp[i + j];
if (j === 0 || j === jmax - 1) {
hphob += 0.5 * ij.stats.hphob;
hphil += 0.5 * ij.stats.hphil;
} else {
hphob += ij.stats.hphob;
hphil += ij.stats.hphil;
}
total += ij.stats.total;
}
const stats = HphobHphil.of(hphob, hphil, total);
if (hphob !== 0) {
const qvaltest = qValue(stats, initialStats);
if (qvaltest > qmax) {
qmax = qvaltest;
membrane = MembraneCandidate.scored(spherePoint, c1, c2, HphobHphil.of(hphob, hphil, total), qmax, centroid);
}
}
}
jmax++;
width = (jmax + 1) * stepSize;
}
}
return membrane!;
}
function qValue(currentStats: HphobHphil, initialStats: HphobHphil): number {
if(initialStats.hphob < 1) {
initialStats.hphob = 0.1;
}
if(initialStats.hphil < 1) {
initialStats.hphil += 1;
}
const part_tot = currentStats.hphob + currentStats.hphil;
return (currentStats.hphob * (initialStats.hphil - currentStats.hphil) - currentStats.hphil * (initialStats.hphob - currentStats.hphob)) /
Math.sqrt(part_tot * initialStats.hphob * initialStats.hphil * (initialStats.hphob + initialStats.hphil - part_tot));
}
export function isInMembranePlane(testPoint: Vec3, normalVector: Vec3, planePoint1: Vec3, planePoint2: Vec3): boolean {
const d1 = -Vec3.dot(normalVector, planePoint1);
const d2 = -Vec3.dot(normalVector, planePoint2);
const d = -Vec3.dot(normalVector, testPoint);
return d > Math.min(d1, d2) && d < Math.max(d1, d2);
}
// generates a defined number of points on a sphere with radius = extent around the specified centroid
function generateSpherePoints(ctx: ANVILContext, numberOfSpherePoints: number): Vec3[] {
const { centroid, extent } = ctx;
const points = [];
let oldPhi = 0, h, theta, phi;
for(let k = 1, kl = numberOfSpherePoints + 1; k < kl; k++) {
h = -1 + 2 * (k - 1) / (numberOfSpherePoints - 1);
theta = Math.acos(h);
phi = (k === 1 || k === numberOfSpherePoints) ? 0 : (oldPhi + 3.6 / Math.sqrt(numberOfSpherePoints * (1 - h * h))) % (2 * Math.PI);
const point = Vec3.create(
extent * Math.sin(phi) * Math.sin(theta) + centroid[0],
extent * Math.cos(theta) + centroid[1],
extent * Math.cos(phi) * Math.sin(theta) + centroid[2]
);
points[k - 1] = point;
oldPhi = phi;
}
return points;
}
// generates sphere points close to that of the initial membrane
function findProximateAxes(ctx: ANVILContext, membrane: MembraneCandidate): Vec3[] {
const { numberOfSpherePoints, extent } = ctx;
const points = generateSpherePoints(ctx, 30000);
let j = 4;
let sphere_pts2: Vec3[] = [];
while (sphere_pts2.length < numberOfSpherePoints) {
const d = 2 * extent / numberOfSpherePoints + j;
const dsq = d * d;
sphere_pts2 = [];
for (let i = 0, il = points.length; i < il; i++) {
if (Vec3.squaredDistance(points[i], membrane.spherePoint!) < dsq) {
sphere_pts2.push(points[i]);
}
}
j += 0.2;
}
return sphere_pts2;
}
interface HphobHphil {
hphob: number,
hphil: number,
total: number
}
namespace HphobHphil {
export function of(hphob: number, hphil: number, total?: number) {
return {
hphob: hphob,
hphil: hphil,
total: !!total ? total : hphob + hphil
};
}
const testPoint = Vec3();
export function filtered(ctx: ANVILContext, label_comp_id: StructureElement.Property<string>, filter?: (test: Vec3) => boolean): HphobHphil {
const { offsets, exposed, structure } = ctx;
const l = StructureElement.Location.create(structure);
const { x, y, z } = StructureProperties.atom;
let hphob = 0;
let hphil = 0;
for (let k = 0, kl = offsets.length; k < kl; k++) {
// ignore buried residues
if (!exposed[k]) {
continue;
}
setLocation(l, structure, offsets[k]);
Vec3.set(testPoint, x(l), y(l), z(l));
// testPoints have to be in putative membrane layer
if (filter && !filter(testPoint)) {
continue;
}
if (isHydrophobic(label_comp_id(l))) {
hphob++;
} else {
hphil++;
}
}
return of(hphob, hphil);
}
}
// ANVIL-specific (not general) definition of membrane-favoring amino acids
const HYDROPHOBIC_AMINO_ACIDS = new Set(['ALA', 'CYS', 'GLY', 'HIS', 'ILE', 'LEU', 'MET', 'PHE', 'SER', 'THR', 'VAL']);
export function isHydrophobic(label_comp_id: string): boolean {
return HYDROPHOBIC_AMINO_ACIDS.has(label_comp_id);
}
function setLocation(l: StructureElement.Location, structure: Structure, serialIndex: number) {
l.structure = structure;
l.unit = structure.units[structure.serialMapping.unitIndices[serialIndex]];
l.element = structure.serialMapping.elementIndices[serialIndex];
return l;
}

View File

@@ -1,174 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../mol-plugin-state/builder/structure/representation-preset';
import { MembraneOrientationProvider, MembraneOrientation } from './prop';
import { StateObjectRef, StateTransformer, StateTransform } from '../../mol-state';
import { Task } from '../../mol-task';
import { PluginBehavior } from '../../mol-plugin/behavior';
import { MembraneOrientationRepresentationProvider, MembraneOrientationParams, MembraneOrientationRepresentation } from './representation';
import { HydrophobicityColorThemeProvider } from '../../mol-theme/color/hydrophobicity';
import { PluginStateObject, PluginStateTransform } from '../../mol-plugin-state/objects';
import { PluginContext } from '../../mol-plugin/context';
import { DefaultQueryRuntimeTable } from '../../mol-script/runtime/query/compiler';
import { StructureSelectionQuery, StructureSelectionCategory } from '../../mol-plugin-state/helpers/structure-selection-query';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { GenericRepresentationRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
const Tag = MembraneOrientation.Tag;
export const ANVILMembraneOrientation = PluginBehavior.create<{ autoAttach: boolean }>({
name: 'anvil-membrane-orientation-prop',
category: 'custom-props',
display: {
name: 'Membrane Orientation',
description: 'Data calculated with ANVIL algorithm.'
},
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
private provider = MembraneOrientationProvider
register(): void {
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
this.ctx.customStructureProperties.register(this.provider, this.params.autoAttach);
this.ctx.representation.structure.registry.add(MembraneOrientationRepresentationProvider);
this.ctx.query.structure.registry.add(isTransmembrane);
this.ctx.genericRepresentationControls.set(Tag.Representation, selection => {
const refs: GenericRepresentationRef[] = [];
selection.structures.forEach(structure => {
const memRepr = structure.genericRepresentations?.filter(r => r.cell.transform.transformer.id === MembraneOrientation3D.id)[0];
if (memRepr) refs.push(memRepr);
});
return [refs, 'Membrane Orientation'];
});
this.ctx.builders.structure.representation.registerPreset(MembraneOrientationPreset);
}
update(p: { autoAttach: boolean }) {
let updated = this.params.autoAttach !== p.autoAttach;
this.params.autoAttach = p.autoAttach;
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
return updated;
}
unregister() {
DefaultQueryRuntimeTable.removeCustomProp(this.provider.descriptor);
this.ctx.customStructureProperties.unregister(this.provider.descriptor.name);
this.ctx.representation.structure.registry.remove(MembraneOrientationRepresentationProvider);
this.ctx.query.structure.registry.remove(isTransmembrane);
this.ctx.genericRepresentationControls.delete(Tag.Representation);
this.ctx.builders.structure.representation.unregisterPreset(MembraneOrientationPreset);
}
},
params: () => ({
autoAttach: PD.Boolean(false)
})
});
//
export const isTransmembrane = StructureSelectionQuery('Residues Embedded in Membrane', MS.struct.modifier.union([
MS.struct.modifier.wholeResidues([
MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
'atom-test': MembraneOrientation.symbols.isTransmembrane.symbol(),
})
])
])
]), {
description: 'Select residues that are embedded between the membrane layers.',
category: StructureSelectionCategory.Residue,
ensureCustomProperties: (ctx, structure) => {
return MembraneOrientationProvider.attach(ctx, structure);
}
});
//
export { MembraneOrientation3D };
type MembraneOrientation3D = typeof MembraneOrientation3D
const MembraneOrientation3D = PluginStateTransform.BuiltIn({
name: 'membrane-orientation-3d',
display: {
name: 'Membrane Orientation',
description: 'Membrane Orientation planes and rims. Data calculated with ANVIL algorithm.'
},
from: PluginStateObject.Molecule.Structure,
to: PluginStateObject.Shape.Representation3D,
params: (a) => {
return {
...MembraneOrientationParams,
};
}
})({
canAutoUpdate({ oldParams, newParams }) {
return true;
},
apply({ a, params }, plugin: PluginContext) {
return Task.create('Membrane Orientation', async ctx => {
await MembraneOrientationProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, a.data);
const repr = MembraneOrientationRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => MembraneOrientationParams);
await repr.createOrUpdate(params, a.data).runInContext(ctx);
return new PluginStateObject.Shape.Representation3D({ repr, source: a }, { label: 'Membrane Orientation' });
});
},
update({ a, b, newParams }, plugin: PluginContext) {
return Task.create('Membrane Orientation', async ctx => {
await MembraneOrientationProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, a.data);
const props = { ...b.data.repr.props, ...newParams };
await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
return StateTransformer.UpdateResult.Updated;
});
},
isApplicable(a) {
return MembraneOrientationProvider.isApplicable(a.data);
}
});
export const MembraneOrientationPreset = StructureRepresentationPresetProvider({
id: 'preset-membrane-orientation',
display: {
name: 'Membrane Orientation', group: 'Annotation',
description: 'Shows orientation of membrane layers. Data calculated with ANVIL algorithm.' // TODO add ' or obtained via RCSB PDB'
},
isApplicable(a) {
return MembraneOrientationProvider.isApplicable(a.data);
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
if (!MembraneOrientationProvider.get(structure).value) {
await plugin.runTask(Task.create('Membrane Orientation', async runtime => {
await MembraneOrientationProvider.attach({ runtime, assetManager: plugin.managers.asset }, structure);
}));
}
const membraneOrientation = await tryCreateMembraneOrientation(plugin, structureCell);
const colorTheme = HydrophobicityColorThemeProvider.name as any;
const preset = await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
return { components: preset.components, representations: { ...preset.representations, membraneOrientation } };
}
});
export function tryCreateMembraneOrientation(plugin: PluginContext, structure: StateObjectRef<PluginStateObject.Molecule.Structure>, params?: StateTransformer.Params<MembraneOrientation3D>, initialState?: Partial<StateTransform.State>) {
const state = plugin.state.data;
const membraneOrientation = state.build().to(structure)
.applyOrUpdateTagged('membrane-orientation-3d', MembraneOrientation3D, params, { state: initialState });
return membraneOrientation.commit({ revertOnError: true });
}

View File

@@ -1,82 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Structure, StructureProperties, Unit } from '../../mol-model/structure';
import { CustomPropertyDescriptor } from '../../mol-model/custom-property';
import { ANVILParams, ANVILProps, computeANVIL, isInMembranePlane } from './algorithm';
import { CustomStructureProperty } from '../../mol-model-props/common/custom-structure-property';
import { CustomProperty } from '../../mol-model-props/common/custom-property';
import { AccessibleSurfaceAreaProvider } from '../../mol-model-props/computed/accessible-surface-area';
import { Vec3 } from '../../mol-math/linear-algebra';
import { QuerySymbolRuntime } from '../../mol-script/runtime/query/base';
import { CustomPropSymbol } from '../../mol-script/language/symbol';
import { Type } from '../../mol-script/language/type';
export const MembraneOrientationParams = {
...ANVILParams
};
export type MembraneOrientationParams = typeof MembraneOrientationParams
export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
export { MembraneOrientation };
interface MembraneOrientation {
// point in membrane boundary
readonly planePoint1: Vec3,
// point in opposite side of membrane boundary
readonly planePoint2: Vec3,
// normal vector of membrane layer
readonly normalVector: Vec3,
// the radius of the membrane layer
readonly radius: number,
readonly centroid: Vec3
}
namespace MembraneOrientation {
export enum Tag {
Representation = 'membrane-orientation-3d'
}
const pos = Vec3();
export const symbols = {
isTransmembrane: QuerySymbolRuntime.Dynamic(CustomPropSymbol('computed', 'membrane-orientation.is-transmembrane', Type.Bool),
ctx => {
const { unit, structure } = ctx.element;
const { x, y, z } = StructureProperties.atom;
if (!Unit.isAtomic(unit)) return 0;
const membraneOrientation = MembraneOrientationProvider.get(structure).value;
if (!membraneOrientation) return 0;
Vec3.set(pos, x(ctx.element), y(ctx.element), z(ctx.element));
const { normalVector, planePoint1, planePoint2 } = membraneOrientation!;
return isInMembranePlane(pos, normalVector, planePoint1, planePoint2);
})
};
}
export const MembraneOrientationProvider: CustomStructureProperty.Provider<MembraneOrientationParams, MembraneOrientation> = CustomStructureProperty.createProvider({
label: 'Membrane Orientation',
descriptor: CustomPropertyDescriptor({
name: 'anvil_computed_membrane_orientation',
symbols: MembraneOrientation.symbols,
// TODO `cifExport`
}),
type: 'root',
defaultParams: MembraneOrientationParams,
getParams: (data: Structure) => MembraneOrientationParams,
isApplicable: (data: Structure) => true,
obtain: async (ctx: CustomProperty.Context, data: Structure, props: Partial<MembraneOrientationProps>) => {
const p = { ...PD.getDefaultValues(MembraneOrientationParams), ...props };
return { value: await computeAnvil(ctx, data, p) };
}
});
async function computeAnvil(ctx: CustomProperty.Context, data: Structure, props: Partial<ANVILProps>): Promise<MembraneOrientation> {
await AccessibleSurfaceAreaProvider.attach(ctx, data);
const p = { ...PD.getDefaultValues(ANVILParams), ...props };
return await computeANVIL(data, p).runInContext(ctx.runtime);
}

View File

@@ -1,156 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../mol-repr/representation';
import { Structure } from '../../mol-model/structure';
import { Spheres } from '../../mol-geo/geometry/spheres/spheres';
import { StructureRepresentationProvider, StructureRepresentation, StructureRepresentationStateBuilder } from '../../mol-repr/structure/representation';
import { MembraneOrientation } from './prop';
import { ThemeRegistryContext } from '../../mol-theme/theme';
import { ShapeRepresentation } from '../../mol-repr/shape/representation';
import { Shape } from '../../mol-model/shape';
import { RuntimeContext } from '../../mol-task';
import { Lines } from '../../mol-geo/geometry/lines/lines';
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
import { LinesBuilder } from '../../mol-geo/geometry/lines/lines-builder';
import { Circle } from '../../mol-geo/primitive/circle';
import { transformPrimitive } from '../../mol-geo/primitive/primitive';
import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
import { MembraneOrientationProvider } from './prop';
import { MarkerActions } from '../../mol-util/marker-action';
import { lociLabel } from '../../mol-theme/label';
import { ColorNames } from '../../mol-util/color/names';
import { CustomProperty } from '../../mol-model-props/common/custom-property';
const SharedParams = {
color: PD.Color(ColorNames.lightgrey),
radiusFactor: PD.Numeric(0.8333, { min: 0.1, max: 3.0, step: 0.01 }, { description: 'Scale the radius of the membrane layer' })
};
const BilayerSpheresParams = {
...Spheres.Params,
...SharedParams,
sphereSize: PD.Numeric(1, { min: 0.1, max: 10, step: 0.1 }, { description: 'Size of spheres that represent membrane planes' }),
density: PD.Numeric(1, { min: 0.25, max: 10, step: 0.25 }, { description: 'Distance between spheres'})
};
export type BilayerSpheresParams = typeof BilayerSpheresParams
export type BilayerSpheresProps = PD.Values<BilayerSpheresParams>
const BilayerPlanesParams = {
...Mesh.Params,
...SharedParams,
sectorOpacity: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
};
export type BilayerPlanesParams = typeof BilayerPlanesParams
export type BilayerPlanesProps = PD.Values<BilayerPlanesParams>
const BilayerRimsParams = {
...Lines.Params,
...SharedParams,
lineSizeAttenuation: PD.Boolean(true),
linesSize: PD.Numeric(0.3, { min: 0.01, max: 50, step: 0.01 }),
dashedLines: PD.Boolean(true),
};
export type BilayerRimsParams = typeof BilayerRimsParams
export type BilayerRimsProps = PD.Values<BilayerRimsParams>
const MembraneOrientationVisuals = {
'bilayer-planes': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerPlanesParams>) => ShapeRepresentation(getBilayerPlanes, Mesh.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }), modifyProps: p => ({ ...p, alpha: p.sectorOpacity, ignoreLight: true, doubleSided: false }) }),
'bilayer-rims': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerRimsParams>) => ShapeRepresentation(getBilayerRims, Lines.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }) })
};
export const MembraneOrientationParams = {
...BilayerSpheresParams,
...BilayerPlanesParams,
...BilayerRimsParams,
visuals: PD.MultiSelect(['bilayer-planes', 'bilayer-rims'], PD.objectToOptions(MembraneOrientationVisuals)),
};
export type MembraneOrientationParams = typeof MembraneOrientationParams
export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
export function getMembraneOrientationParams(ctx: ThemeRegistryContext, structure: Structure) {
return PD.clone(MembraneOrientationParams);
}
export type MembraneOrientationRepresentation = StructureRepresentation<MembraneOrientationParams>
export function MembraneOrientationRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MembraneOrientationParams>): MembraneOrientationRepresentation {
return Representation.createMulti('Membrane Orientation', ctx, getParams, StructureRepresentationStateBuilder, MembraneOrientationVisuals as unknown as Representation.Def<Structure, MembraneOrientationParams>);
}
export const MembraneOrientationRepresentationProvider = StructureRepresentationProvider({
name: 'membrane-orientation',
label: 'Membrane Orientation',
description: 'Displays a grid of points representing membrane layers.',
factory: MembraneOrientationRepresentation,
getParams: getMembraneOrientationParams,
defaultValues: PD.getDefaultValues(MembraneOrientationParams),
defaultColorTheme: { name: 'shape-group' },
defaultSizeTheme: { name: 'shape-group' },
isApplicable: (structure: Structure) => structure.elementCount > 0,
ensureCustomProperties: {
attach: (ctx: CustomProperty.Context, structure: Structure) => MembraneOrientationProvider.attach(ctx, structure, void 0, true),
detach: (data) => MembraneOrientationProvider.ref(data, false)
}
});
function membraneLabel(data: Structure) {
return `${lociLabel(Structure.Loci(data))} | Membrane Orientation`;
}
function getBilayerRims(ctx: RuntimeContext, data: Structure, props: BilayerRimsProps, shape?: Shape<Lines>): Shape<Lines> {
const { planePoint1: p1, planePoint2: p2, centroid, normalVector: normal, radius } = MembraneOrientationProvider.get(data).value!;
const scaledRadius = props.radiusFactor * radius;
const builder = LinesBuilder.create(128, 64, shape?.geometry);
getLayerCircle(builder, p1, centroid, normal, scaledRadius, props);
getLayerCircle(builder, p2, centroid, normal, scaledRadius, props);
return Shape.create('Bilayer rims', data, builder.getLines(), () => props.color, () => props.linesSize, () => membraneLabel(data));
}
function getLayerCircle(builder: LinesBuilder, p: Vec3, centroid: Vec3, normal: Vec3, radius: number, props: BilayerRimsProps, shape?: Shape<Lines>) {
const circle = getCircle(p, centroid, normal, radius);
const { indices, vertices } = circle;
for (let j = 0, jl = indices.length; j < jl; j += 3) {
if (props.dashedLines && j % 2 === 1) continue; // draw every other segment to get dashes
const start = indices[j] * 3;
const end = indices[j + 1] * 3;
const startX = vertices[start];
const startY = vertices[start + 1];
const startZ = vertices[start + 2];
const endX = vertices[end];
const endY = vertices[end + 1];
const endZ = vertices[end + 2];
builder.add(startX, startY, startZ, endX, endY, endZ, 0);
}
}
const tmpMat = Mat4();
function getCircle(p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
Mat4.targetTo(tmpMat, p, centroid, normal);
Mat4.setTranslation(tmpMat, p);
Mat4.mul(tmpMat, tmpMat, Mat4.rotX90);
const circle = Circle({ radius, segments: 64 });
return transformPrimitive(circle, tmpMat);
}
function getBilayerPlanes(ctx: RuntimeContext, data: Structure, props: BilayerPlanesProps, shape?: Shape<Mesh>): Shape<Mesh> {
const { planePoint1: p1, planePoint2: p2, centroid, normalVector: normal, radius } = MembraneOrientationProvider.get(data).value!;
const state = MeshBuilder.createState(128, 64, shape && shape.geometry);
const scaledRadius = props.radiusFactor * radius;
getLayerPlane(state, p1, centroid, normal, scaledRadius);
getLayerPlane(state, p2, centroid, normal, scaledRadius);
return Shape.create('Bilayer planes', data, MeshBuilder.getMesh(state), () => props.color, () => 1, () => membraneLabel(data));
}
function getLayerPlane(state: MeshBuilder.State, p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
const circle = getCircle(p, centroid, normal, radius);
state.currentGroup = 0;
MeshBuilder.addPrimitive(state, Mat4.id, circle);
MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle);
}

View File

@@ -1,95 +0,0 @@
/**
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ThemeDataContext } from '../../../mol-theme/theme';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Color } from '../../../mol-util/color';
import { getPalette } from '../../../mol-util/color/palette';
import { ColorTheme, LocationColor } from '../../../mol-theme/color';
import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
import { StructureElement, Bond, Model } from '../../../mol-model/structure';
import { Location } from '../../../mol-model/location';
import { CellPackInfoProvider } from '../property';
import { distinctColors } from '../../../mol-util/color/distinct';
import { Hcl } from '../../../mol-util/color/spaces/hcl';
const DefaultColor = Color(0xCCCCCC);
const Description = 'Gives every model in a CellPack packing a unique generated color similar to other models in the packing.';
export const CellPackGenerateColorThemeParams = {};
export type CellPackGenerateColorThemeParams = typeof CellPackGenerateColorThemeParams
export function getCellPackGenerateColorThemeParams(ctx: ThemeDataContext) {
return CellPackGenerateColorThemeParams; // TODO return copy
}
export function CellPackGenerateColorTheme(ctx: ThemeDataContext, props: PD.Values<CellPackGenerateColorThemeParams>): ColorTheme<CellPackGenerateColorThemeParams> {
let color: LocationColor;
let legend: ScaleLegend | TableLegend | undefined;
const info = ctx.structure && CellPackInfoProvider.get(ctx.structure).value;
if (ctx.structure && info) {
const colors = distinctColors(info.packingsCount);
let hcl = Hcl.fromColor(Hcl(), colors[info.packingIndex]);
const hue = [Math.max(0, hcl[0] - 35), Math.min(360, hcl[0] + 35)] as [number, number];
const { models } = ctx.structure.root;
let size = 0;
for (const m of models) size = Math.max(size, Model.TrajectoryInfo.get(m).size);
const palette = getPalette(size, { palette: {
name: 'generate',
params: {
hue, chroma: [30, 80], luminance: [15, 85],
clusteringStepCount: 50, minSampleCount: 800, maxCount: 75
}
}}, { minLabel: 'Min', maxLabel: 'Max' });
legend = palette.legend;
const modelColor = new Map<number, Color>();
for (let i = 0, il = models.length; i < il; ++i) {
const idx = Model.TrajectoryInfo.get(models[i]).index;
modelColor.set(Model.TrajectoryInfo.get(models[i]).index, palette.color(idx));
}
color = (location: Location): Color => {
if (StructureElement.Location.is(location)) {
return modelColor.get(Model.TrajectoryInfo.get(location.unit.model).index)!;
} else if (Bond.isLocation(location)) {
return modelColor.get(Model.TrajectoryInfo.get(location.aUnit.model).index)!;
}
return DefaultColor;
};
} else {
color = () => DefaultColor;
}
return {
factory: CellPackGenerateColorTheme,
granularity: 'instance',
color,
props,
description: Description,
legend
};
}
export const CellPackGenerateColorThemeProvider: ColorTheme.Provider<CellPackGenerateColorThemeParams, 'cellpack-generate'> = {
name: 'cellpack-generate',
label: 'CellPack Generate',
category: ColorTheme.Category.Chain,
factory: CellPackGenerateColorTheme,
getParams: getCellPackGenerateColorThemeParams,
defaultValues: PD.getDefaultValues(CellPackGenerateColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => {
return (
!!ctx.structure && ctx.structure.elementCount > 0 &&
!!CellPackInfoProvider.get(ctx.structure).value
);
}
};

View File

@@ -1,75 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ThemeDataContext } from '../../../mol-theme/theme';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Color } from '../../../mol-util/color';
import { ColorTheme, LocationColor } from '../../../mol-theme/color';
import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
import { StructureElement, Model, Bond } from '../../../mol-model/structure';
import { Location } from '../../../mol-model/location';
import { CellPackInfoProvider } from '../property';
const DefaultColor = Color(0xCCCCCC);
const Description = 'Gives every model in a CellPack the color provied in the packing data.';
export const CellPackProvidedColorThemeParams = {};
export type CellPackProvidedColorThemeParams = typeof CellPackProvidedColorThemeParams
export function getCellPackProvidedColorThemeParams(ctx: ThemeDataContext) {
return CellPackProvidedColorThemeParams; // TODO return copy
}
export function CellPackProvidedColorTheme(ctx: ThemeDataContext, props: PD.Values<CellPackProvidedColorThemeParams>): ColorTheme<CellPackProvidedColorThemeParams> {
let color: LocationColor;
let legend: ScaleLegend | TableLegend | undefined;
const info = ctx.structure && CellPackInfoProvider.get(ctx.structure).value;
if (ctx.structure && info?.colors) {
const { models } = ctx.structure.root;
const modelColor = new Map<number, Color>();
for (let i = 0, il = models.length; i < il; ++i) {
const idx = Model.TrajectoryInfo.get(models[i]).index;
modelColor.set(Model.TrajectoryInfo.get(models[i]).index, info.colors[idx]);
}
color = (location: Location): Color => {
if (StructureElement.Location.is(location)) {
return modelColor.get(Model.TrajectoryInfo.get(location.unit.model).index)!;
} else if (Bond.isLocation(location)) {
return modelColor.get(Model.TrajectoryInfo.get(location.aUnit.model).index)!;
}
return DefaultColor;
};
} else {
color = () => DefaultColor;
}
return {
factory: CellPackProvidedColorTheme,
granularity: 'instance',
color,
props,
description: Description,
legend
};
}
export const CellPackProvidedColorThemeProvider: ColorTheme.Provider<CellPackProvidedColorThemeParams, 'cellpack-provided'> = {
name: 'cellpack-provided',
label: 'CellPack Provided',
category: ColorTheme.Category.Chain,
factory: CellPackProvidedColorTheme,
getParams: getCellPackProvidedColorThemeParams,
defaultValues: PD.getDefaultValues(CellPackProvidedColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => {
return (
!!ctx.structure && ctx.structure.elementCount > 0 &&
Model.TrajectoryInfo.get(ctx.structure.models[0]).size > 1 &&
!!CellPackInfoProvider.get(ctx.structure).value?.colors
);
}
};

View File

@@ -1,229 +0,0 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Ludovic Autin <autin@scripps.edu>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Quat, Mat4 } from '../../mol-math/linear-algebra';
import { NumberArray } from '../../mol-util/type-helpers';
interface Frame {
t: Vec3,
r: Vec3,
s: Vec3,
}
const a0Tmp = Vec3();
const a1Tmp = Vec3();
const a2Tmp = Vec3();
const a3Tmp = Vec3();
function CubicInterpolate(out: Vec3, y0: Vec3, y1: Vec3, y2: Vec3, y3: Vec3, mu: number): Vec3 {
const mu2 = mu * mu;
Vec3.sub(a0Tmp, y3, y2);
Vec3.sub(a0Tmp, a0Tmp, y0);
Vec3.add(a0Tmp, a0Tmp, y1);
Vec3.sub(a1Tmp, y0, y1);
Vec3.sub(a1Tmp, a1Tmp, a0Tmp);
Vec3.sub(a2Tmp, y2, y0);
Vec3.copy(a3Tmp, y1);
out[0] = a0Tmp[0] * mu * mu2 + a1Tmp[0] * mu2 + a2Tmp[0] * mu + a3Tmp[0];
out[1] = a0Tmp[1] * mu * mu2 + a1Tmp[1] * mu2 + a2Tmp[1] * mu + a3Tmp[1];
out[2] = a0Tmp[2] * mu * mu2 + a1Tmp[2] * mu2 + a2Tmp[2] * mu + a3Tmp[2];
return out;
}
const cp0 = Vec3();
const cp1 = Vec3();
const cp2 = Vec3();
const cp3 = Vec3();
const currentPosition = Vec3();
function ResampleControlPoints(points: NumberArray, segmentLength: number) {
const nP = points.length / 3;
// insert a point at the end and at the begining
// controlPoints.Insert(0, controlPoints[0] + (controlPoints[0] - controlPoints[1]) / 2.0f);
// controlPoints.Add(controlPoints[nP - 1] + (controlPoints[nP - 1] - controlPoints[nP - 2]) / 2.0f);
let resampledControlPoints: Vec3[] = [];
// resampledControlPoints.Add(controlPoints[0]);
// resampledControlPoints.Add(controlPoints[1]);
let idx = 1;
// const currentPosition = Vec3.create(points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2])
Vec3.fromArray(currentPosition, points, idx * 3);
let lerpValue = 0.0;
// Normalize the distance between control points
while (true) {
if (idx + 2 >= nP) break;
Vec3.fromArray(cp0, points, (idx - 1) * 3);
Vec3.fromArray(cp1, points, idx * 3);
Vec3.fromArray(cp2, points, (idx + 1) * 3);
Vec3.fromArray(cp3, points, (idx + 2) * 3);
// const cp0 = Vec3.create(points[(idx-1)*3], points[(idx-1)*3+1], points[(idx-1)*3+2]) // controlPoints[currentPointId - 1];
// const cp1 = Vec3.create(points[idx*3], points[idx*3+1], points[idx*3+2]) // controlPoints[currentPointId];
// const cp2 = Vec3.create(points[(idx+1)*3], points[(idx+1)*3+1], points[(idx+1)*3+2]) // controlPoints[currentPointId + 1];
// const cp3 = Vec3.create(points[(idx+2)*3], points[(idx+2)*3+1], points[(idx+2)*3+2]); // controlPoints[currentPointId + 2];
let found = false;
for (; lerpValue <= 1; lerpValue += 0.01) {
// lerp?slerp
// let candidate:Vec3 = Vec3.lerp(Vec3.zero(), cp0, cp1, lerpValue);
// const candidate:Vec3 = Vec3.bezier(Vec3.zero(), cp0, cp1, cp2, cp3, lerpValue);
const candidate = CubicInterpolate(Vec3(), cp0, cp1, cp2, cp3, lerpValue);
const d = Vec3.distance(currentPosition, candidate);
if (d > segmentLength) {
resampledControlPoints.push(candidate);
Vec3.copy(currentPosition, candidate);
found = true;
break;
}
}
if (!found) {
lerpValue = 0;
idx += 1;
}
}
return resampledControlPoints;
}
const prevV = Vec3();
const tmpV1 = Vec3();
const tmpV2 = Vec3();
const tmpV3 = Vec3();
// easier to align to theses normals
function GetSmoothNormals(points: Vec3[]) {
const nP: number = points.length;
const smoothNormals: Vec3[] = [];
if (points.length < 3) {
for (let i = 0; i < points.length; ++i)
smoothNormals.push(Vec3.normalize(Vec3(), points[i]));
return smoothNormals;
}
let p0 = points[0];
let p1 = points[1];
let p2 = points[2];
const p21 = Vec3.sub(tmpV1, p2, p1);
const p01 = Vec3.sub(tmpV2, p0, p1);
const p0121 = Vec3.cross(tmpV3, p01, p21);
Vec3.normalize(prevV, p0121);
smoothNormals.push(Vec3.clone(prevV));
for (let i = 1; i < points.length - 1; ++i) {
p0 = points[i - 1];
p1 = points[i];
p2 = points[i + 1];
const t = Vec3.normalize(tmpV1, Vec3.sub(tmpV1, p2, p0));
const b = Vec3.normalize(tmpV2, Vec3.cross(tmpV2, t, prevV));
const n = Vec3.normalize(Vec3(), Vec3.cross(tmpV3, t, b));
Vec3.negate(n, n);
Vec3.copy(prevV, n);
smoothNormals.push(n);
}
const last = Vec3();
Vec3.normalize(last, Vec3.cross(last,
Vec3.sub(tmpV1, points[nP - 3], points[nP - 2]),
Vec3.sub(tmpV2, points[nP - 2], points[nP - 1]))
);
smoothNormals.push(last);
return smoothNormals;
}
const frameTmpV1 = Vec3();
const frameTmpV2 = Vec3();
const frameTmpV3 = Vec3();
function getFrame(reference: Vec3, tangent: Vec3) {
const t = Vec3.normalize(Vec3(), tangent);
// make reference vector orthogonal to tangent
const proj_r_to_t = Vec3.scale(
frameTmpV1, tangent, Vec3.dot(reference, tangent) / Vec3.dot(tangent, tangent)
);
const r = Vec3.normalize(Vec3(), Vec3.sub(frameTmpV2, reference, proj_r_to_t));
// make bitangent vector orthogonal to the others
const s = Vec3.normalize(Vec3(), Vec3.cross(frameTmpV3, t, r));
return { t, r, s };
}
const mfTmpV1 = Vec3();
const mfTmpV2 = Vec3();
const mfTmpV3 = Vec3();
const mfTmpV4 = Vec3();
const mfTmpV5 = Vec3();
const mfTmpV6 = Vec3();
const mfTmpV7 = Vec3();
const mfTmpV8 = Vec3();
const mfTmpV9 = Vec3();
// easier to align to theses normals
// https://github.com/bzamecnik/gpg/blob/master/rotation-minimizing-frame/rmf.py
function GetMiniFrame(points: Vec3[], normals: Vec3[]) {
const frames: Frame[] = [];
const t0 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[1], points[0]));
frames.push(getFrame(normals[0], t0));
for (let i = 0; i < points.length - 2; ++i) {
const t2 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[i + 2], points[i + 1]));
const v1 = Vec3.sub(mfTmpV2, points[i + 1], points[i]); // this is tangeant
const c1 = Vec3.dot(v1, v1);
// compute r_i^L = R_1 * r_i
const v1r = Vec3.scale(mfTmpV3, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].r));
const ref_L_i = Vec3.sub(mfTmpV4, frames[i].r, v1r);
// compute t_i^L = R_1 * t_i
const v1t = Vec3.scale(mfTmpV5, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].t));
const tan_L_i = Vec3.sub(mfTmpV6, frames[i].t, v1t);
// # compute reflection vector of R_2
const v2 = Vec3.sub(mfTmpV7, t2, tan_L_i);
const c2 = Vec3.dot(v2, v2);
// compute r_(i+1) = R_2 * r_i^L
const v2l = Vec3.scale(mfTmpV8, v1, (2.0 / c2) * Vec3.dot(v2, ref_L_i));
const ref_next = Vec3.sub(mfTmpV9, ref_L_i, v2l); // ref_L_i - (2 / c2) * v2.dot(ref_L_i) * v2
frames.push(getFrame(ref_next, t2)); // frames.append(Frame(ref_next, tangents[i+1]))
}
return frames;
}
const rpTmpVec1 = Vec3();
export function getMatFromResamplePoints(points: NumberArray, segmentLength: number, resample: boolean) {
let new_points: Vec3[] = [];
if (resample) new_points = ResampleControlPoints(points, segmentLength);
else {
for (let idx = 0; idx < points.length / 3; ++idx){
new_points.push(Vec3.fromArray(Vec3.zero(), points, idx * 3));
}
}
const npoints = new_points.length;
const new_normal = GetSmoothNormals(new_points);
const frames = GetMiniFrame(new_points, new_normal);
const limit = npoints;
const transforms: Mat4[] = [];
const pti = Vec3.copy(rpTmpVec1, new_points[0]);
for (let i = 0; i < npoints - 2; ++i) {
const pti1: Vec3 = new_points[i + 1]; // Vec3.create(points[(i+1)*3],points[(i+1)*3+1],points[(i+1)*3+2]);
const d = Vec3.distance(pti, pti1);
if (d >= segmentLength) {
// use twist or random?
const quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t); // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal
const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random() * 3.60 ); // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();//
const m = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)); // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat));
// let pos:Vec3 = Vec3.add(Vec3.zero(),pti1,pti)
// pos = Vec3.scale(pos,pos,1.0/2.0);
// Vec3.makeRotation(Mat4.zero(),Vec3.create(0,0,1),frames[i].t);//
Mat4.setTranslation(m, pti1);
// let m2:Mat4 = GetTubePropertiesMatrix(pti,pti1);
// let q:Quat = Quat.rotationTo(Quat.zero(), Vec3.create(0,1,0),Vec3.create(0,0,1))
// m2=Mat4.mul(Mat4.identity(),Mat4.fromQuat(Mat4.zero(),q),m2);
transforms.push(m);
Vec3.copy(pti, pti1);
}
if (transforms.length >= limit) break;
}
return transforms;
}

View File

@@ -1,84 +0,0 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Quat } from '../../mol-math/linear-algebra';
export interface CellPack {
cell: Cell
packings: CellPacking[]
}
export interface CellPacking {
name: string,
location: 'surface' | 'interior' | 'cytoplasme',
ingredients: Packing['ingredients']
}
//
export interface Cell {
recipe: Recipe
cytoplasme?: Packing
compartments?: { [key: string]: Compartment }
}
export interface Recipe {
setupfile: string
paths: [string, string][] // [name: string, path: string][]
version: string
name: string
}
export interface Compartment {
surface?: Packing
interior?: Packing
}
export interface Packing {
ingredients: { [key: string]: Ingredient }
}
export interface Positions {
coords?: Vec3[];
}
export interface Radii {
radii?: number[];
}
export interface Ingredient {
source: IngredientSource;
results: [Vec3, Quat][];
name: string;
/** Vec3[]];CoarseGraind Beads coordinates LOD */
positions?: [Positions];
/** number[]];CoarseGraind Beads radii LOD */
radii?: [Radii];
/** Number of `curveX` properties in the object where `X` is a 0-indexed number */
nbCurve?: number;
uLength?: number;
/** Curve properties are Vec3[] but that is not expressable in TypeScript */
[curveX: string]: unknown;
/** the orientation in the membrane */
principalAxis?: Vec3;
/** offset along membrane */
offset?: Vec3;
ingtype?: string;
color?: Vec3;
confidence?: number;
}
export interface IngredientSource {
pdb: string;
bu?: string; /** biological unit e.g AU,BU1,etc.. */
selection?: string; /** NGL selection or :A or :B etc.. */
model?: string; /** model number e.g 0,1,2... */
transform: {
center: boolean;
translate?: Vec3;
};
biomt?: boolean;
}

View File

@@ -1,32 +0,0 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { PluginBehavior } from '../../mol-plugin/behavior';
import { LoadCellPackModel } from './model';
import { CellPackGenerateColorThemeProvider } from './color/generate';
import { CellPackProvidedColorThemeProvider } from './color/provided';
export const CellPack = PluginBehavior.create<{ autoAttach: boolean, showTooltip: boolean }>({
name: 'cellpack',
category: 'custom-props',
display: {
name: 'CellPack',
description: 'CellPack Model Loading and Viewing.'
},
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
register(): void {
this.ctx.state.data.actions.add(LoadCellPackModel);
this.ctx.representation.structure.themes.colorThemeRegistry.add(CellPackGenerateColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.add(CellPackProvidedColorThemeProvider);
}
unregister() {
this.ctx.state.data.actions.remove(LoadCellPackModel);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(CellPackGenerateColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(CellPackProvidedColorThemeProvider);
}
}
});

Some files were not shown because too many files have changed in this diff Show More