mirror of
https://github.com/molstar/molstar.git
synced 2026-06-05 14:04:36 +08:00
Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c0e7e84da | ||
|
|
0d1e105343 | ||
|
|
f040c89ab3 | ||
|
|
5e9d8298ef | ||
|
|
7766ca2793 | ||
|
|
fb2f22f120 | ||
|
|
146fed3504 | ||
|
|
0b7a6e3375 | ||
|
|
f1fbdeaca0 | ||
|
|
ee7e37f6bc | ||
|
|
861f665ab3 | ||
|
|
456de23ad4 | ||
|
|
6d3578c17e | ||
|
|
57da7267e2 | ||
|
|
578b764406 | ||
|
|
f65a38a085 | ||
|
|
d187757bbc | ||
|
|
df83b24cf4 | ||
|
|
8e31ce0f5b | ||
|
|
4f69eb7963 | ||
|
|
4b9009216b | ||
|
|
895076c837 | ||
|
|
6e398ee64a | ||
|
|
c2177272b5 | ||
|
|
4877de5839 | ||
|
|
3cb9d10126 | ||
|
|
23c53cd9fb | ||
|
|
3471743a63 | ||
|
|
1b0b1809ef | ||
|
|
0833cffead | ||
|
|
a0a8ae88b7 | ||
|
|
e415cbeca4 | ||
|
|
4c15c93381 | ||
|
|
bd19822112 | ||
|
|
b87beb4a6e | ||
|
|
62a58facb2 | ||
|
|
5fa8178df7 | ||
|
|
d6043e7d1f | ||
|
|
8e432dfbb4 | ||
|
|
324ab3744b | ||
|
|
33ee4d0418 | ||
|
|
cbb104ccba | ||
|
|
0bda5461ae | ||
|
|
4096a03de1 | ||
|
|
fbee5f83df | ||
|
|
84a1b19850 | ||
|
|
1df5bd6d03 | ||
|
|
8bd4221a85 | ||
|
|
4d97ccdfb3 | ||
|
|
ca5e57ddbf | ||
|
|
ed6511799b | ||
|
|
9b1223ec15 | ||
|
|
97210ee67a | ||
|
|
308d1003ad | ||
|
|
ce9e193958 | ||
|
|
2a83afa8c1 | ||
|
|
8891fa328b | ||
|
|
a23c06c456 | ||
|
|
34e87121e1 | ||
|
|
6e5c20f442 | ||
|
|
8ac3bec451 | ||
|
|
5128d0f405 | ||
|
|
6ae2121391 | ||
|
|
749e0c5a47 | ||
|
|
7b55ef85e1 | ||
|
|
23ec35d1f9 | ||
|
|
ff089c2b9f | ||
|
|
1ab088718a | ||
|
|
0cb2e5857a | ||
|
|
7c5ae5d7ee | ||
|
|
6e2665d98d | ||
|
|
b3b4692237 | ||
|
|
55ff1d4999 | ||
|
|
511c839237 | ||
|
|
384cd6e5d9 | ||
|
|
6fd9dcc72e | ||
|
|
12ca06fe91 | ||
|
|
652f6c651b | ||
|
|
7dd808a772 | ||
|
|
945e55f8a7 | ||
|
|
866a30abe5 | ||
|
|
f0e33e1e4e | ||
|
|
8723ca38b4 | ||
|
|
efffca0026 | ||
|
|
6c5eb3035f | ||
|
|
0bf385f2ca | ||
|
|
9d5f51f513 | ||
|
|
a1448131d8 | ||
|
|
664cacc7ac | ||
|
|
1aec37dd05 | ||
|
|
3ff2c0840e | ||
|
|
5ca3c3ac52 | ||
|
|
714ee50965 | ||
|
|
ae1df3c5aa | ||
|
|
28afb39550 | ||
|
|
3466a8a024 | ||
|
|
90db3321f5 | ||
|
|
bf4e5ed7c2 | ||
|
|
d3b2c20c26 | ||
|
|
c3afabb4b1 | ||
|
|
18cc9790d1 |
4
.github/workflows/node.yml
vendored
4
.github/workflows/node.yml
vendored
@@ -9,12 +9,12 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 17
|
||||
node-version: 16
|
||||
- run: npm ci
|
||||
- run: sudo apt-get install xvfb
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
- name: Test
|
||||
run: xvfb-run --auto-servernum npm run jest
|
||||
run: npm install --no-save "gl@^5.0.0" && xvfb-run --auto-servernum npm run jest
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
43
CHANGELOG.md
43
CHANGELOG.md
@@ -6,6 +6,49 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.6.2] - 2022-04-05
|
||||
|
||||
- ModelServer ligand queries: fixes for alternate locations, additional atoms & UNL ligand
|
||||
- React 18 friendly ``useBehavior`` hook.
|
||||
|
||||
## [v3.6.1] - 2022-04-03
|
||||
|
||||
- Fix React18 related UI regressions.
|
||||
|
||||
## [v3.6.0] - 2022-04-03
|
||||
|
||||
- Check that model and coordinates have same element count when creating a trajectory
|
||||
- Fix aromatic rings assignment: do not mix flags and planarity test
|
||||
- Improve bonds assignment of coarse grained models: check for IndexPairBonds and exhaustive StructConn
|
||||
- Fix unit mapping in bondedAtomicPairs MolScript query
|
||||
- Improve pdb parsing: handle non unique atom and chain names (fixes #156)
|
||||
- Fix volume streaming for entries with multiple contour lists
|
||||
- Add ``allowTransparentBackfaces`` parameter to support double-sided rendering of transparent geometries
|
||||
- Fix handling of case insensitive mmCIF enumeration fields (including entity.type)
|
||||
- Fix ``disable-wboit`` Viewer GET param
|
||||
- Add support for React 18.
|
||||
- Used by importing ``createPluginUI`` from ``mol-plugin-ui/react18``;
|
||||
- In Mol* 4.0, React 18 will become the default option.
|
||||
|
||||
## [v3.5.0] - 2022-03-25
|
||||
|
||||
- Fix issues with bounding-sphere & color-smoothing (mostly for small geometries)
|
||||
- Support BCIF => CIF conversion in ``cif2bcif`` CLI tool
|
||||
|
||||
## [v3.4.0] - 2022-03-13
|
||||
|
||||
- Fix handling of mmcif with empty ``label_*`` fields
|
||||
- Improve saccharide detection (compare against list from CCD)
|
||||
- Fix legend label of hydrophobicity color theme
|
||||
- Add ``LoadTrajectory`` action
|
||||
- Add ``CustomImportControls`` to left panel
|
||||
- Add Zenodo import extension (load structures, trajectories, volumes, and zip files)
|
||||
- Fix loading of some compressed files within sessions
|
||||
- Fix wrong element assignment for atoms with Charmm ion names
|
||||
- Fix handling of empty symmetry cell data
|
||||
- Add support for ``trr`` and ``nctraj`` coordinates files
|
||||
- Add support for ``prmtop`` and ``top`` topology files
|
||||
|
||||
## [v3.3.1] - 2022-02-27
|
||||
|
||||
- Fix issue with unit boundary reuse (do at visual level instead)
|
||||
|
||||
10
README.md
10
README.md
@@ -120,6 +120,9 @@ and navigate to `build/viewer`
|
||||
|
||||
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-ions.js src/mol-model/structure/model/types/ions.ts
|
||||
|
||||
**Saccharide names**
|
||||
|
||||
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-saccharides.js src/mol-model/structure/model/types/saccharides.ts
|
||||
|
||||
**GraphQL schemas**
|
||||
|
||||
@@ -138,7 +141,7 @@ and navigate to `build/viewer`
|
||||
|
||||
export NODE_PATH="lib"; node build/state-docs
|
||||
|
||||
**Convert any CIF to BinaryCIF**
|
||||
**Convert any CIF to BinaryCIF (or vice versa)**
|
||||
|
||||
node lib/commonjs/servers/model/preprocess -i file.cif -ob file.bcif
|
||||
|
||||
@@ -148,6 +151,11 @@ Or
|
||||
|
||||
node lib/commonjs/cli/cif2bcif
|
||||
|
||||
E.g.
|
||||
|
||||
node lib/commonjs/cli/cif2bcif src.cif out.bcif.gz
|
||||
node lib/commonjs/cli/cif2bcif src.bcif.gz out.cif
|
||||
|
||||
## Development
|
||||
|
||||
### Installation
|
||||
|
||||
585
package-lock.json
generated
585
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
38
package.json
38
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.3.1",
|
||||
"version": "3.6.2",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -94,38 +94,42 @@
|
||||
"@graphql-codegen/add": "^3.1.1",
|
||||
"@graphql-codegen/cli": "^2.6.2",
|
||||
"@graphql-codegen/time": "^3.1.1",
|
||||
"@graphql-codegen/typescript": "^2.4.5",
|
||||
"@graphql-codegen/typescript": "^2.4.7",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^2.1.1",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.3.7",
|
||||
"@graphql-codegen/typescript-operations": "^2.3.2",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.4.2",
|
||||
"@graphql-codegen/typescript-operations": "^2.3.4",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/gl": "^4.1.0",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"@types/react": "^17.0.43",
|
||||
"@types/react-dom": "^17.0.14",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^7.0.0",
|
||||
"cpx2": "^4.2.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.6.0",
|
||||
"eslint": "^8.10.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"eslint": "^8.11.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^10.0.1",
|
||||
"graphql": "^16.3.0",
|
||||
"http-server": "^14.1.0",
|
||||
"jest": "^27.5.1",
|
||||
"mini-css-extract-plugin": "^2.5.3",
|
||||
"mini-css-extract-plugin": "^2.6.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"sass": "^1.49.9",
|
||||
"sass-loader": "^12.6.0",
|
||||
"simple-git": "^3.2.6",
|
||||
"simple-git": "^3.3.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-jest": "^27.1.3",
|
||||
"typescript": "^4.5.5",
|
||||
"webpack": "^5.69.1",
|
||||
"typescript": "^4.6.3",
|
||||
"webpack": "^5.70.0",
|
||||
"webpack-cli": "^4.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -135,8 +139,6 @@
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/node": "^16.11.26",
|
||||
"@types/node-fetch": "^2.6.1",
|
||||
"@types/react": "^17.0.39",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"@types/swagger-ui-dist": "3.30.1",
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.19.2",
|
||||
@@ -147,14 +149,14 @@
|
||||
"immer": "^9.0.12",
|
||||
"immutable": "^4.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"rxjs": "^7.5.4",
|
||||
"swagger-ui-dist": "^4.5.2",
|
||||
"rxjs": "^7.5.5",
|
||||
"swagger-ui-dist": "^4.6.2",
|
||||
"tslib": "^2.3.1",
|
||||
"util.promisify": "^1.1.1",
|
||||
"xhr2": "^0.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.2 || ^16.14.0",
|
||||
"react-dom": "^17.0.2 || ^16.14.0"
|
||||
"react": "^18.0.0 || ^17.0.2 || ^16.14.0",
|
||||
"react-dom": "^18.0.0 || ^17.0.2 || ^16.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { Structure } from '../../mol-model/structure';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { PluginStateObject as PSO, PluginStateTransform } from '../../mol-plugin-state/objects';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui/react18';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
|
||||
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
|
||||
@@ -17,20 +17,22 @@ import { ModelExport } from '../../extensions/model-export';
|
||||
import { Mp4Export } from '../../extensions/mp4-export';
|
||||
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
|
||||
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
|
||||
import { ZenodoImport } from '../../extensions/zenodo';
|
||||
import { Volume } from '../../mol-model/volume';
|
||||
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
|
||||
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
|
||||
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
|
||||
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
|
||||
import { BuildInStructureFormat } from '../../mol-plugin-state/formats/structure';
|
||||
import { BuiltInTopologyFormat } from '../../mol-plugin-state/formats/topology';
|
||||
import { BuiltInCoordinatesFormat } from '../../mol-plugin-state/formats/coordinates';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
|
||||
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui/react18';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
@@ -63,6 +65,7 @@ const Extensions = {
|
||||
'mp4-export': PluginSpec.Behavior(Mp4Export),
|
||||
'geo-export': PluginSpec.Behavior(GeometryExport),
|
||||
'ma-quality-assessment': PluginSpec.Behavior(MAQualityAssessment),
|
||||
'zenodo-import': PluginSpec.Behavior(ZenodoImport),
|
||||
};
|
||||
|
||||
const DefaultViewerOptions = {
|
||||
@@ -453,11 +456,11 @@ export interface VolumeIsovalueInfo {
|
||||
export interface LoadTrajectoryParams {
|
||||
model: { kind: 'model-url', url: string, format?: BuiltInTrajectoryFormat /* mmcif */, isBinary?: boolean }
|
||||
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array, format?: BuiltInTrajectoryFormat /* mmcif */ }
|
||||
| { kind: 'topology-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
|
||||
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
|
||||
| { kind: 'topology-url', url: string, format: BuiltInTopologyFormat, isBinary?: boolean }
|
||||
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInTopologyFormat },
|
||||
modelLabel?: string,
|
||||
coordinates: { kind: 'coordinates-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
|
||||
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
|
||||
coordinates: { kind: 'coordinates-url', url: string, format: BuiltInCoordinatesFormat, isBinary?: boolean }
|
||||
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInCoordinatesFormat },
|
||||
coordinatesLabel?: string,
|
||||
preset?: keyof PresetTrajectoryHierarchy
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
pixelScale: parseFloat(pixelScale) || 1,
|
||||
pickScale: parseFloat(pickScale) || 0.25,
|
||||
pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
|
||||
enableWboit: disableWboit ? true : void 0, // use default value if disable-wboit is not set
|
||||
enableWboit: disableWboit ? false : void 0, // use default value if disable-wboit is not set
|
||||
preferWebgl1: preferWebgl1,
|
||||
}).then(viewer => {
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
|
||||
77
src/cli/chem-comp-dict/create-saccharides.ts
Normal file
77
src/cli/chem-comp-dict/create-saccharides.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2022 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 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 extractSaccharideNames(ccd: DatabaseCollection<CCD_Schema>) {
|
||||
const saccharideNames: string[] = [];
|
||||
for (const k in ccd) {
|
||||
const { chem_comp } = ccd[k];
|
||||
const type = chem_comp.type.value(0).toUpperCase();
|
||||
if (type.includes('SACCHARIDE')) {
|
||||
saccharideNames.push(chem_comp.id.value(0));
|
||||
}
|
||||
}
|
||||
// these are extra saccharides that don't have SACCHARIDE in their type
|
||||
saccharideNames.push(
|
||||
'UMQ', // UNDECYL-MALTOSIDE, via GlyFinder
|
||||
'SQD', // SULFOQUINOVOSYLDIACYLGLYCEROL, via GlyFinder
|
||||
);
|
||||
return saccharideNames;
|
||||
}
|
||||
|
||||
function writeSaccharideNamesFile(filePath: string, ionNames: string[]) {
|
||||
const output = `/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated ion names params file. Names extracted from CCD components.
|
||||
*
|
||||
* @author molstar/cli/chem-comp-dict/create-saccharides
|
||||
*/
|
||||
|
||||
export const SaccharideNames = 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 saccharideNames = extractSaccharideNames(ccd);
|
||||
if (!fs.existsSync(path.dirname(out))) {
|
||||
fs.mkdirSync(path.dirname(out));
|
||||
}
|
||||
writeSaccharideNamesFile(out, saccharideNames);
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Extract and save SaccharideNames from CCD.'
|
||||
});
|
||||
parser.add_argument('out', {
|
||||
help: 'Generated file output path.'
|
||||
});
|
||||
parser.add_argument('--forceDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of CCD and PVCD.'
|
||||
});
|
||||
interface Args {
|
||||
out: string,
|
||||
forceDownload?: boolean,
|
||||
}
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
run(args.out, args.forceDownload);
|
||||
@@ -71,7 +71,7 @@ function classify(name: string, field: CifField): CifWriter.Field {
|
||||
}
|
||||
|
||||
export function convert(path: string, asText = false, hints?: EncodingStrategyHint[], filter?: string) {
|
||||
return Task.create<Uint8Array>('BinaryCIF', async ctx => {
|
||||
return Task.create<Uint8Array>('Convert CIF', async ctx => {
|
||||
const encodingProvider: BinaryEncodingProvider = hints
|
||||
? CifWriter.createEncodingProviderFromJsonConfig(hints)
|
||||
: { get: (c, f) => void 0 };
|
||||
|
||||
@@ -18,7 +18,7 @@ async function process(srcPath: string, outPath: string, configPath?: string, fi
|
||||
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);
|
||||
const res = await convert(srcPath, srcPath.toLowerCase().indexOf('.bcif') > 0, config, filter);
|
||||
await write(outPath, res);
|
||||
}
|
||||
|
||||
@@ -38,13 +38,13 @@ function run(args: Args) {
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Convert any CIF file to a BCIF file'
|
||||
description: 'Convert any BCIF file to a CIF file or vice versa'
|
||||
});
|
||||
parser.add_argument('src', {
|
||||
help: 'Source CIF path'
|
||||
help: 'Source file path'
|
||||
});
|
||||
parser.add_argument('out', {
|
||||
help: 'Output BCIF path'
|
||||
help: 'Output file path'
|
||||
});
|
||||
parser.add_argument('-c', '--config', {
|
||||
help: 'Optional encoding strategy/precision config path',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -13,15 +13,17 @@ export function getFieldType(type: string, description: string, values?: string[
|
||||
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 'ucode':
|
||||
case 'uline':
|
||||
case 'uchar3':
|
||||
case 'uchar1':
|
||||
// only force lower-case for enums
|
||||
return values && values.length ? EnumCol(values.map(x => x.toLowerCase()), 'lstr', description) : StrCol(description);
|
||||
case 'aliasname':
|
||||
case 'name':
|
||||
case 'idname':
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -10,7 +10,7 @@ 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.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated '${name}' schema file. ${info}
|
||||
*
|
||||
@@ -35,13 +35,17 @@ function getTypeShorthands(schema: Database, fields?: Filter) {
|
||||
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 col = schema.tables[table].columns[columnName];
|
||||
if (col.type === 'enum') types.add(col.subType);
|
||||
types.add(col.type);
|
||||
});
|
||||
});
|
||||
const shorthands: string[] = [];
|
||||
types.forEach(type => {
|
||||
switch (type) {
|
||||
case 'str': shorthands.push('const str = Schema.str;'); break;
|
||||
case 'ustr': shorthands.push('const ustr = Schema.ustr;'); break;
|
||||
case 'lstr': shorthands.push('const lstr = Schema.lstr;'); 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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -29,8 +29,8 @@ export function FloatCol(description: string): FloatCol { return { type: 'float'
|
||||
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 {
|
||||
export type EnumCol = { type: 'enum', subType: 'int' | 'str' | 'ustr' | 'lstr', values: string[] } & BaseCol
|
||||
export function EnumCol(values: string[], subType: 'int' | 'str' | 'ustr' | 'lstr', description: string): EnumCol {
|
||||
return { type: 'enum', description, values, subType };
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/spherical-f
|
||||
import { BasisAndOrbitals, CreateOrbitalDensityVolume, CreateOrbitalRepresentation3D, CreateOrbitalVolume, StaticBasisAndOrbitals } from '../../extensions/alpha-orbitals/transforms';
|
||||
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui/react18';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
@@ -80,20 +80,24 @@ export class AlphaOrbitalsExample {
|
||||
|
||||
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).`
|
||||
this.plugin.behaviors.canvas3d.initialized.subscribe(init => {
|
||||
if (!init) return;
|
||||
|
||||
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
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.load({
|
||||
moleculeSdf: DemoMoleculeSDF,
|
||||
...DemoOrbitals
|
||||
mountControls(this, document.getElementById('controls')!);
|
||||
});
|
||||
|
||||
mountControls(this, document.getElementById('controls')!);
|
||||
}
|
||||
|
||||
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { EmptyLoci } from '../../mol-model/loci';
|
||||
import { StructureSelection } from '../../mol-model/structure';
|
||||
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui/react18';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { Canvas3DProps } from '../../mol-canvas3d/canvas3d';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui/react18';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
|
||||
@@ -10,7 +10,7 @@ import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/mod
|
||||
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 { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui/react18';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { CreateVolumeStreamingInfo, InitVolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
|
||||
|
||||
@@ -32,6 +32,7 @@ import { Color } from '../../mol-util/color';
|
||||
import { objectForEach } from '../../mol-util/object';
|
||||
import { readFromFile } from '../../mol-util/data-source';
|
||||
import { ColorNames } from '../../mol-util/color/names';
|
||||
import { createBasic } from '../../mol-model-formats/structure/basic/schema';
|
||||
|
||||
function getCellPackModelUrl(fileName: string, baseUrl: string) {
|
||||
return `${baseUrl}/results/${fileName}`;
|
||||
@@ -310,7 +311,8 @@ async function getCurve(plugin: PluginContext, name: string, ingredient: Ingredi
|
||||
const cif = getCifCurve(name, transforms, model);
|
||||
const curveModelTask = Task.create('Curve Model', async ctx => {
|
||||
const format = MmcifFormat.fromFrame(cif);
|
||||
const models = await createModels(format.data.db, format, ctx);
|
||||
const basic = createBasic(format.data.db, true);
|
||||
const models = await createModels(basic, format, ctx);
|
||||
return models.representative;
|
||||
});
|
||||
|
||||
|
||||
@@ -11,149 +11,248 @@ import { Location } from '../../../mol-model/location';
|
||||
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
|
||||
import { ColorTheme } from '../../../mol-theme/color';
|
||||
import { ThemeDataContext } from '../../../mol-theme/theme';
|
||||
import { Color } from '../../../mol-util/color';
|
||||
import { Color, ColorMap } from '../../../mol-util/color';
|
||||
import { getColorMapParams } from '../../../mol-util/color/params';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { TableLegend } from '../../../mol-util/legend';
|
||||
import { iterableToArray } from '../../../mol-data/util';
|
||||
import { ObjectKeys } from '../../../mol-util/type-helpers';
|
||||
|
||||
const DefaultColor = Color(0xCCCCCC);
|
||||
const Description = 'Assigns colors to confal pyramids';
|
||||
|
||||
const DefaultClassColors = {
|
||||
A: 0xFFC1C1,
|
||||
B: 0xC8CFFF,
|
||||
BII: 0x0059DA,
|
||||
miB: 0x3BE8FB,
|
||||
Z: 0x01F60E,
|
||||
IC: 0xFA5CFB,
|
||||
OPN: 0xE90000,
|
||||
SYN: 0xFFFF01,
|
||||
N: 0xF2F2F2,
|
||||
};
|
||||
const ErrorColor = Color(0xFFA10A);
|
||||
|
||||
type ConformerClasses = 'A' | 'B' | 'BII' | 'miB' | 'Z' | 'IC' | 'OPN' | 'SYN' | 'N';
|
||||
const PyramidsColors = ColorMap({
|
||||
NANT_Upr: DefaultClassColors.N,
|
||||
NANT_Lwr: DefaultClassColors.N,
|
||||
AA00_Upr: DefaultClassColors.A,
|
||||
AA00_Lwr: DefaultClassColors.A,
|
||||
AA02_Upr: DefaultClassColors.A,
|
||||
AA02_Lwr: DefaultClassColors.A,
|
||||
AA03_Upr: DefaultClassColors.A,
|
||||
AA03_Lwr: DefaultClassColors.A,
|
||||
AA04_Upr: DefaultClassColors.A,
|
||||
AA04_Lwr: DefaultClassColors.A,
|
||||
AA08_Upr: DefaultClassColors.A,
|
||||
AA08_Lwr: DefaultClassColors.A,
|
||||
AA09_Upr: DefaultClassColors.A,
|
||||
AA09_Lwr: DefaultClassColors.A,
|
||||
AA01_Upr: DefaultClassColors.A,
|
||||
AA01_Lwr: DefaultClassColors.A,
|
||||
AA05_Upr: DefaultClassColors.A,
|
||||
AA05_Lwr: DefaultClassColors.A,
|
||||
AA06_Upr: DefaultClassColors.A,
|
||||
AA06_Lwr: DefaultClassColors.A,
|
||||
AA10_Upr: DefaultClassColors.A,
|
||||
AA10_Lwr: DefaultClassColors.A,
|
||||
AA11_Upr: DefaultClassColors.A,
|
||||
AA11_Lwr: DefaultClassColors.A,
|
||||
AA07_Upr: DefaultClassColors.A,
|
||||
AA07_Lwr: DefaultClassColors.A,
|
||||
AA12_Upr: DefaultClassColors.A,
|
||||
AA12_Lwr: DefaultClassColors.A,
|
||||
AA13_Upr: DefaultClassColors.A,
|
||||
AA13_Lwr: DefaultClassColors.A,
|
||||
AB01_Upr: DefaultClassColors.A,
|
||||
AB01_Lwr: DefaultClassColors.B,
|
||||
AB02_Upr: DefaultClassColors.A,
|
||||
AB02_Lwr: DefaultClassColors.B,
|
||||
AB03_Upr: DefaultClassColors.A,
|
||||
AB03_Lwr: DefaultClassColors.B,
|
||||
AB04_Upr: DefaultClassColors.A,
|
||||
AB04_Lwr: DefaultClassColors.B,
|
||||
AB05_Upr: DefaultClassColors.A,
|
||||
AB05_Lwr: DefaultClassColors.B,
|
||||
BA01_Upr: DefaultClassColors.B,
|
||||
BA01_Lwr: DefaultClassColors.A,
|
||||
BA05_Upr: DefaultClassColors.B,
|
||||
BA05_Lwr: DefaultClassColors.A,
|
||||
BA09_Upr: DefaultClassColors.B,
|
||||
BA09_Lwr: DefaultClassColors.A,
|
||||
BA08_Upr: DefaultClassColors.BII,
|
||||
BA08_Lwr: DefaultClassColors.A,
|
||||
BA10_Upr: DefaultClassColors.B,
|
||||
BA10_Lwr: DefaultClassColors.A,
|
||||
BA13_Upr: DefaultClassColors.BII,
|
||||
BA13_Lwr: DefaultClassColors.A,
|
||||
BA16_Upr: DefaultClassColors.BII,
|
||||
BA16_Lwr: DefaultClassColors.A,
|
||||
BA17_Upr: DefaultClassColors.BII,
|
||||
BA17_Lwr: DefaultClassColors.A,
|
||||
BB00_Upr: DefaultClassColors.B,
|
||||
BB00_Lwr: DefaultClassColors.B,
|
||||
BB01_Upr: DefaultClassColors.B,
|
||||
BB01_Lwr: DefaultClassColors.B,
|
||||
BB17_Upr: DefaultClassColors.B,
|
||||
BB17_Lwr: DefaultClassColors.B,
|
||||
BB02_Upr: DefaultClassColors.B,
|
||||
BB02_Lwr: DefaultClassColors.B,
|
||||
BB03_Upr: DefaultClassColors.B,
|
||||
BB03_Lwr: DefaultClassColors.B,
|
||||
BB11_Upr: DefaultClassColors.B,
|
||||
BB11_Lwr: DefaultClassColors.B,
|
||||
BB16_Upr: DefaultClassColors.B,
|
||||
BB16_Lwr: DefaultClassColors.B,
|
||||
BB04_Upr: DefaultClassColors.B,
|
||||
BB04_Lwr: DefaultClassColors.BII,
|
||||
BB05_Upr: DefaultClassColors.B,
|
||||
BB05_Lwr: DefaultClassColors.BII,
|
||||
BB07_Upr: DefaultClassColors.BII,
|
||||
BB07_Lwr: DefaultClassColors.BII,
|
||||
BB08_Upr: DefaultClassColors.BII,
|
||||
BB08_Lwr: DefaultClassColors.BII,
|
||||
BB10_Upr: DefaultClassColors.miB,
|
||||
BB10_Lwr: DefaultClassColors.miB,
|
||||
BB12_Upr: DefaultClassColors.miB,
|
||||
BB12_Lwr: DefaultClassColors.miB,
|
||||
BB13_Upr: DefaultClassColors.miB,
|
||||
BB13_Lwr: DefaultClassColors.miB,
|
||||
BB14_Upr: DefaultClassColors.miB,
|
||||
BB14_Lwr: DefaultClassColors.miB,
|
||||
BB15_Upr: DefaultClassColors.miB,
|
||||
BB15_Lwr: DefaultClassColors.miB,
|
||||
BB20_Upr: DefaultClassColors.miB,
|
||||
BB20_Lwr: DefaultClassColors.miB,
|
||||
IC01_Upr: DefaultClassColors.IC,
|
||||
IC01_Lwr: DefaultClassColors.IC,
|
||||
IC02_Upr: DefaultClassColors.IC,
|
||||
IC02_Lwr: DefaultClassColors.IC,
|
||||
IC03_Upr: DefaultClassColors.IC,
|
||||
IC03_Lwr: DefaultClassColors.IC,
|
||||
IC04_Upr: DefaultClassColors.IC,
|
||||
IC04_Lwr: DefaultClassColors.IC,
|
||||
IC05_Upr: DefaultClassColors.IC,
|
||||
IC05_Lwr: DefaultClassColors.IC,
|
||||
IC06_Upr: DefaultClassColors.IC,
|
||||
IC06_Lwr: DefaultClassColors.IC,
|
||||
IC07_Upr: DefaultClassColors.IC,
|
||||
IC07_Lwr: DefaultClassColors.IC,
|
||||
OP01_Upr: DefaultClassColors.OPN,
|
||||
OP01_Lwr: DefaultClassColors.OPN,
|
||||
OP02_Upr: DefaultClassColors.OPN,
|
||||
OP02_Lwr: DefaultClassColors.OPN,
|
||||
OP03_Upr: DefaultClassColors.OPN,
|
||||
OP03_Lwr: DefaultClassColors.OPN,
|
||||
OP04_Upr: DefaultClassColors.OPN,
|
||||
OP04_Lwr: DefaultClassColors.OPN,
|
||||
OP05_Upr: DefaultClassColors.OPN,
|
||||
OP05_Lwr: DefaultClassColors.OPN,
|
||||
OP06_Upr: DefaultClassColors.OPN,
|
||||
OP06_Lwr: DefaultClassColors.OPN,
|
||||
OP07_Upr: DefaultClassColors.OPN,
|
||||
OP07_Lwr: DefaultClassColors.OPN,
|
||||
OP08_Upr: DefaultClassColors.OPN,
|
||||
OP08_Lwr: DefaultClassColors.OPN,
|
||||
OP09_Upr: DefaultClassColors.OPN,
|
||||
OP09_Lwr: DefaultClassColors.OPN,
|
||||
OP10_Upr: DefaultClassColors.OPN,
|
||||
OP10_Lwr: DefaultClassColors.OPN,
|
||||
OP11_Upr: DefaultClassColors.OPN,
|
||||
OP11_Lwr: DefaultClassColors.OPN,
|
||||
OP12_Upr: DefaultClassColors.OPN,
|
||||
OP12_Lwr: DefaultClassColors.OPN,
|
||||
OP13_Upr: DefaultClassColors.OPN,
|
||||
OP13_Lwr: DefaultClassColors.OPN,
|
||||
OP14_Upr: DefaultClassColors.OPN,
|
||||
OP14_Lwr: DefaultClassColors.OPN,
|
||||
OP15_Upr: DefaultClassColors.OPN,
|
||||
OP15_Lwr: DefaultClassColors.OPN,
|
||||
OP16_Upr: DefaultClassColors.OPN,
|
||||
OP16_Lwr: DefaultClassColors.OPN,
|
||||
OP17_Upr: DefaultClassColors.OPN,
|
||||
OP17_Lwr: DefaultClassColors.OPN,
|
||||
OP18_Upr: DefaultClassColors.OPN,
|
||||
OP18_Lwr: DefaultClassColors.OPN,
|
||||
OP19_Upr: DefaultClassColors.OPN,
|
||||
OP19_Lwr: DefaultClassColors.OPN,
|
||||
OP20_Upr: DefaultClassColors.OPN,
|
||||
OP20_Lwr: DefaultClassColors.OPN,
|
||||
OP21_Upr: DefaultClassColors.OPN,
|
||||
OP21_Lwr: DefaultClassColors.OPN,
|
||||
OP22_Upr: DefaultClassColors.OPN,
|
||||
OP22_Lwr: DefaultClassColors.OPN,
|
||||
OP23_Upr: DefaultClassColors.OPN,
|
||||
OP23_Lwr: DefaultClassColors.OPN,
|
||||
OP24_Upr: DefaultClassColors.OPN,
|
||||
OP24_Lwr: DefaultClassColors.OPN,
|
||||
OP25_Upr: DefaultClassColors.OPN,
|
||||
OP25_Lwr: DefaultClassColors.OPN,
|
||||
OP26_Upr: DefaultClassColors.OPN,
|
||||
OP26_Lwr: DefaultClassColors.OPN,
|
||||
OP27_Upr: DefaultClassColors.OPN,
|
||||
OP27_Lwr: DefaultClassColors.OPN,
|
||||
OP28_Upr: DefaultClassColors.OPN,
|
||||
OP28_Lwr: DefaultClassColors.OPN,
|
||||
OP29_Upr: DefaultClassColors.OPN,
|
||||
OP29_Lwr: DefaultClassColors.OPN,
|
||||
OP30_Upr: DefaultClassColors.OPN,
|
||||
OP30_Lwr: DefaultClassColors.OPN,
|
||||
OP31_Upr: DefaultClassColors.OPN,
|
||||
OP31_Lwr: DefaultClassColors.OPN,
|
||||
OPS1_Upr: DefaultClassColors.OPN,
|
||||
OPS1_Lwr: DefaultClassColors.OPN,
|
||||
OP1S_Upr: DefaultClassColors.OPN,
|
||||
OP1S_Lwr: DefaultClassColors.SYN,
|
||||
AAS1_Upr: DefaultClassColors.SYN,
|
||||
AAS1_Lwr: DefaultClassColors.A,
|
||||
AB1S_Upr: DefaultClassColors.A,
|
||||
AB1S_Lwr: DefaultClassColors.SYN,
|
||||
AB2S_Upr: DefaultClassColors.A,
|
||||
AB2S_Lwr: DefaultClassColors.SYN,
|
||||
BB1S_Upr: DefaultClassColors.B,
|
||||
BB1S_Lwr: DefaultClassColors.SYN,
|
||||
BB2S_Upr: DefaultClassColors.B,
|
||||
BB2S_Lwr: DefaultClassColors.SYN,
|
||||
BBS1_Upr: DefaultClassColors.SYN,
|
||||
BBS1_Lwr: DefaultClassColors.B,
|
||||
ZZ01_Upr: DefaultClassColors.Z,
|
||||
ZZ01_Lwr: DefaultClassColors.Z,
|
||||
ZZ02_Upr: DefaultClassColors.Z,
|
||||
ZZ02_Lwr: DefaultClassColors.Z,
|
||||
ZZ1S_Upr: DefaultClassColors.Z,
|
||||
ZZ1S_Lwr: DefaultClassColors.SYN,
|
||||
ZZ2S_Upr: DefaultClassColors.Z,
|
||||
ZZ2S_Lwr: DefaultClassColors.SYN,
|
||||
ZZS1_Upr: DefaultClassColors.SYN,
|
||||
ZZS1_Lwr: DefaultClassColors.Z,
|
||||
ZZS2_Upr: DefaultClassColors.SYN,
|
||||
ZZS2_Lwr: DefaultClassColors.Z,
|
||||
});
|
||||
type PyramidsColors = typeof PyramidsColors;
|
||||
|
||||
const ColorMapping: ReadonlyMap<ConformerClasses, Color> = new Map([
|
||||
['A', Color(0xFFC1C1)],
|
||||
['B', Color(0xC8CFFF)],
|
||||
['BII', Color(0x0059DA)],
|
||||
['miB', Color(0x3BE8FB)],
|
||||
['Z', Color(0x01F60E)],
|
||||
['IC', Color(0xFA5CFB)],
|
||||
['OPN', Color(0xE90000)],
|
||||
['SYN', Color(0xFFFF01)],
|
||||
['N', Color(0xF2F2F2)],
|
||||
]);
|
||||
export const ConfalPyramidsColorThemeParams = {
|
||||
colors: PD.MappedStatic('default', {
|
||||
'default': PD.EmptyGroup(),
|
||||
'custom': PD.Group(getColorMapParams(PyramidsColors))
|
||||
}),
|
||||
};
|
||||
export type ConfalPyramidsColorThemeParams = typeof ConfalPyramidsColorThemeParams;
|
||||
|
||||
const NtCToClasses: ReadonlyMap<string, [ConformerClasses, ConformerClasses]> = new Map([
|
||||
['NANT', ['N', 'N']],
|
||||
['AA00', ['A', 'A']],
|
||||
['AA02', ['A', 'A']],
|
||||
['AA03', ['A', 'A']],
|
||||
['AA04', ['A', 'A']],
|
||||
['AA08', ['A', 'A']],
|
||||
['AA09', ['A', 'A']],
|
||||
['AA01', ['A', 'A']],
|
||||
['AA05', ['A', 'A']],
|
||||
['AA06', ['A', 'A']],
|
||||
['AA10', ['A', 'A']],
|
||||
['AA11', ['A', 'A']],
|
||||
['AA07', ['A', 'A']],
|
||||
['AA12', ['A', 'A']],
|
||||
['AA13', ['A', 'A']],
|
||||
['AB01', ['A', 'B']],
|
||||
['AB02', ['A', 'B']],
|
||||
['AB03', ['A', 'B']],
|
||||
['AB04', ['A', 'B']],
|
||||
['AB05', ['A', 'B']],
|
||||
['BA01', ['B', 'A']],
|
||||
['BA05', ['B', 'A']],
|
||||
['BA09', ['B', 'A']],
|
||||
['BA08', ['BII', 'A']],
|
||||
['BA10', ['B', 'A']],
|
||||
['BA13', ['BII', 'A']],
|
||||
['BA16', ['BII', 'A']],
|
||||
['BA17', ['BII', 'A']],
|
||||
['BB00', ['B', 'B']],
|
||||
['BB01', ['B', 'B']],
|
||||
['BB17', ['B', 'B']],
|
||||
['BB02', ['B', 'B']],
|
||||
['BB03', ['B', 'B']],
|
||||
['BB11', ['B', 'B']],
|
||||
['BB16', ['B', 'B']],
|
||||
['BB04', ['B', 'BII']],
|
||||
['BB05', ['B', 'BII']],
|
||||
['BB07', ['BII', 'BII']],
|
||||
['BB08', ['BII', 'BII']],
|
||||
['BB10', ['miB', 'miB']],
|
||||
['BB12', ['miB', 'miB']],
|
||||
['BB13', ['miB', 'miB']],
|
||||
['BB14', ['miB', 'miB']],
|
||||
['BB15', ['miB', 'miB']],
|
||||
['BB20', ['miB', 'miB']],
|
||||
['IC01', ['IC', 'IC']],
|
||||
['IC02', ['IC', 'IC']],
|
||||
['IC03', ['IC', 'IC']],
|
||||
['IC04', ['IC', 'IC']],
|
||||
['IC05', ['IC', 'IC']],
|
||||
['IC06', ['IC', 'IC']],
|
||||
['IC07', ['IC', 'IC']],
|
||||
['OP01', ['OPN', 'OPN']],
|
||||
['OP02', ['OPN', 'OPN']],
|
||||
['OP03', ['OPN', 'OPN']],
|
||||
['OP04', ['OPN', 'OPN']],
|
||||
['OP05', ['OPN', 'OPN']],
|
||||
['OP06', ['OPN', 'OPN']],
|
||||
['OP07', ['OPN', 'OPN']],
|
||||
['OP08', ['OPN', 'OPN']],
|
||||
['OP09', ['OPN', 'OPN']],
|
||||
['OP10', ['OPN', 'OPN']],
|
||||
['OP11', ['OPN', 'OPN']],
|
||||
['OP12', ['OPN', 'OPN']],
|
||||
['OP13', ['OPN', 'OPN']],
|
||||
['OP14', ['OPN', 'OPN']],
|
||||
['OP15', ['OPN', 'OPN']],
|
||||
['OP16', ['OPN', 'OPN']],
|
||||
['OP17', ['OPN', 'OPN']],
|
||||
['OP18', ['OPN', 'OPN']],
|
||||
['OP19', ['OPN', 'OPN']],
|
||||
['OP20', ['OPN', 'OPN']],
|
||||
['OP21', ['OPN', 'OPN']],
|
||||
['OP22', ['OPN', 'OPN']],
|
||||
['OP23', ['OPN', 'OPN']],
|
||||
['OP24', ['OPN', 'OPN']],
|
||||
['OP25', ['OPN', 'OPN']],
|
||||
['OP26', ['OPN', 'OPN']],
|
||||
['OP27', ['OPN', 'OPN']],
|
||||
['OP28', ['OPN', 'OPN']],
|
||||
['OP29', ['OPN', 'OPN']],
|
||||
['OP30', ['OPN', 'OPN']],
|
||||
['OP31', ['OPN', 'OPN']],
|
||||
['OPS1', ['OPN', 'OPN']],
|
||||
['OP1S', ['OPN', 'SYN']],
|
||||
['AAS1', ['SYN', 'A']],
|
||||
['AB1S', ['A', 'SYN']],
|
||||
['AB2S', ['A', 'SYN']],
|
||||
['BB1S', ['B', 'SYN']],
|
||||
['BB2S', ['B', 'SYN']],
|
||||
['BBS1', ['SYN', 'B']],
|
||||
['ZZ01', ['Z', 'Z']],
|
||||
['ZZ02', ['Z', 'Z']],
|
||||
['ZZ1S', ['Z', 'SYN']],
|
||||
['ZZ2S', ['Z', 'SYN']],
|
||||
['ZZS1', ['SYN', 'Z']],
|
||||
['ZZS2', ['SYN', 'Z']],
|
||||
]);
|
||||
|
||||
function getConformerColor(ntc: string, useLower: boolean): Color {
|
||||
const item = NtCToClasses.get(ntc);
|
||||
if (!item) return ErrorColor;
|
||||
return ColorMapping.get(useLower ? item[1] : item[0]) ?? ErrorColor;
|
||||
}
|
||||
|
||||
export const ConfalPyramidsColorThemeParams = {};
|
||||
export type ConfalPyramidsColorThemeParams = typeof ConfalPyramidsColorThemeParams
|
||||
export function getConfalPyramidsColorThemeParams(ctx: ThemeDataContext) {
|
||||
return ConfalPyramidsColorThemeParams; // TODO return copy
|
||||
return PD.clone(ConfalPyramidsColorThemeParams);
|
||||
}
|
||||
|
||||
export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values<ConfalPyramidsColorThemeParams>): ColorTheme<ConfalPyramidsColorThemeParams> {
|
||||
const colorMap = props.colors.name === 'default' ? PyramidsColors : props.colors.params;
|
||||
|
||||
function color(location: Location, isSecondary: boolean): Color {
|
||||
if (CPT.isLocation(location)) {
|
||||
const { pyramid, isLower } = location.data;
|
||||
return getConformerColor(pyramid.NtC, isLower);
|
||||
const key = pyramid.NtC + `_${isLower ? 'Lwr' : 'Upr'}` as keyof PyramidsColors;
|
||||
return colorMap[key] ?? ErrorColor;
|
||||
}
|
||||
|
||||
return DefaultColor;
|
||||
return ErrorColor;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -162,12 +261,7 @@ export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values
|
||||
color,
|
||||
props,
|
||||
description: Description,
|
||||
legend: TableLegend(iterableToArray(ColorMapping.entries()).map(([conformer, color]) => {
|
||||
return [conformer, color] as [string, Color];
|
||||
}).concat([
|
||||
['Error', ErrorColor],
|
||||
['Unknown', DefaultColor]
|
||||
]))
|
||||
legend: TableLegend(ObjectKeys(colorMap).map(k => [k.replace('_', ' '), colorMap[k]] as [string, Color]).concat([['Error', ErrorColor]])),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -123,10 +123,8 @@ function createPyramidsFromCif(model: Model,
|
||||
|
||||
for (let i = 0; i < _rowCount; i++) {
|
||||
const model_num = PDB_model_number.value(i);
|
||||
if (model_num !== model.modelNum) {
|
||||
if (model_num !== model.modelNum)
|
||||
hasMultipleModels = true;
|
||||
continue; // We are only interested in data for the current model
|
||||
}
|
||||
|
||||
const { _NtC, _confal_score } = getNtCAndConfalScore(id.value(i), i, stepsSummary);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { ConfalPyramidsProvider } from './property';
|
||||
import { ConfalPyramidsTypes as CPT } from './types';
|
||||
import { OrderedSet, Segmentation } from '../../../mol-data/int';
|
||||
import { Segmentation } from '../../../mol-data/int';
|
||||
import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, StructureProperties, Unit } from '../../../mol-model/structure';
|
||||
|
||||
@@ -63,15 +63,12 @@ export namespace ConfalPyramidsUtil {
|
||||
return prop.data.hasMultipleModels;
|
||||
}
|
||||
|
||||
function getPossibleAltIdsIndices(eIFirst: ElementIndex, eILast: ElementIndex, structure: Structure, unit: Unit.Atomic): string[] {
|
||||
const loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
|
||||
|
||||
const uIFirst = OrderedSet.indexOf(unit.elements, eIFirst);
|
||||
const uILast = OrderedSet.indexOf(unit.elements, eILast);
|
||||
|
||||
function getPossibleAltIds(residue: Residue, structure: Structure, unit: Unit.Atomic): string[] {
|
||||
const possibleAltIds: string[] = [];
|
||||
for (let uI = uIFirst; uI <= uILast; uI++) {
|
||||
loc.element = unit.elements[uI];
|
||||
|
||||
const loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
|
||||
for (let rI = residue.start; rI <= residue.end - 1; rI++) {
|
||||
loc.element = unit.elements[rI];
|
||||
const altId = StructureProperties.atom.label_alt_id(loc);
|
||||
if (altId !== '' && !possibleAltIds.includes(altId)) possibleAltIds.push(altId);
|
||||
}
|
||||
@@ -79,10 +76,6 @@ export namespace ConfalPyramidsUtil {
|
||||
return possibleAltIds;
|
||||
}
|
||||
|
||||
function getPossibleAltIdsResidue(residue: Residue, structure: Structure, unit: Unit.Atomic): string[] {
|
||||
return getPossibleAltIdsIndices(unit.elements[residue.start], unit.elements[residue.end - 1], structure, unit);
|
||||
}
|
||||
|
||||
class Utility {
|
||||
protected getPyramidByName(name: string): { pyramid: CPT.Pyramid | undefined, index: number } {
|
||||
const index = this.data.names.get(name);
|
||||
@@ -122,19 +115,22 @@ export namespace ConfalPyramidsUtil {
|
||||
|
||||
export class UnitWalker extends Utility {
|
||||
private getAtomIndices(names: string[], residue: Residue): ElementIndex[] {
|
||||
let rI = residue.start;
|
||||
const rILast = residue.end - 1;
|
||||
const indices: ElementIndex[] = [];
|
||||
|
||||
for (; rI !== rILast; rI++) {
|
||||
const eI = this.unit.elements[rI];
|
||||
const loc = StructureElement.Location.create(this.structure, this.unit, eI);
|
||||
const loc = StructureElement.Location.create(this.structure, this.unit, -1 as ElementIndex);
|
||||
for (let rI = residue.start; rI <= residue.end - 1; rI++) {
|
||||
loc.element = this.unit.elements[rI];
|
||||
const thisName = StructureProperties.atom.label_atom_id(loc);
|
||||
if (names.includes(thisName)) indices.push(eI);
|
||||
if (names.includes(thisName)) indices.push(loc.element);
|
||||
}
|
||||
|
||||
if (indices.length === 0)
|
||||
throw new Error(`Element ${name} not found on residue ${residue.index}`);
|
||||
if (indices.length === 0) {
|
||||
let namesStr = '';
|
||||
for (const n of names)
|
||||
namesStr += `${n} `;
|
||||
|
||||
throw new Error(`Element [${namesStr}] not found on residue ${residue.index}`);
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
@@ -257,12 +253,12 @@ export namespace ConfalPyramidsUtil {
|
||||
}
|
||||
|
||||
private step(residue: Residue): { firstAtoms: FirstResidueAtoms[], secondAtoms: SecondResidueAtoms[] } {
|
||||
const firstPossibleAltIds = getPossibleAltIdsResidue(residue, this.structure, this.unit);
|
||||
const firstPossibleAltIds = getPossibleAltIds(residue, this.structure, this.unit);
|
||||
const firstAtoms = this.processFirstResidue(residue, firstPossibleAltIds);
|
||||
|
||||
residue = this.residueIt.move();
|
||||
|
||||
const secondPossibleAltIds = getPossibleAltIdsResidue(residue, this.structure, this.unit);
|
||||
const secondPossibleAltIds = getPossibleAltIds(residue, this.structure, this.unit);
|
||||
const secondAtoms = this.processSecondResidue(residue, secondPossibleAltIds);
|
||||
|
||||
return { firstAtoms, secondAtoms };
|
||||
|
||||
30
src/extensions/zenodo/index.ts
Normal file
30
src/extensions/zenodo/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { PluginBehavior } from '../../mol-plugin/behavior/behavior';
|
||||
import { ZenodoImportUI } from './ui';
|
||||
|
||||
export const ZenodoImport = PluginBehavior.create<{ }>({
|
||||
name: 'extension-zenodo-import',
|
||||
category: 'misc',
|
||||
display: {
|
||||
name: 'Zenodo Export'
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ }> {
|
||||
register(): void {
|
||||
this.ctx.customImportControls.set('zenodo-import', ZenodoImportUI as any);
|
||||
}
|
||||
|
||||
update() {
|
||||
return false;
|
||||
}
|
||||
|
||||
unregister() {
|
||||
this.ctx.customImportControls.delete('zenodo-import');
|
||||
}
|
||||
},
|
||||
params: () => ({ })
|
||||
});
|
||||
302
src/extensions/zenodo/ui.tsx
Normal file
302
src/extensions/zenodo/ui.tsx
Normal file
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { DownloadFile } from '../../mol-plugin-state/actions/file';
|
||||
import { DownloadStructure, LoadTrajectory } from '../../mol-plugin-state/actions/structure';
|
||||
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
|
||||
import { CoordinatesFormatCategory } from '../../mol-plugin-state/formats/coordinates';
|
||||
import { TopologyFormatCategory } from '../../mol-plugin-state/formats/topology';
|
||||
import { TrajectoryFormatCategory } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { VolumeFormatCategory } from '../../mol-plugin-state/formats/volume';
|
||||
import { CollapsableControls, CollapsableState } from '../../mol-plugin-ui/base';
|
||||
import { Button } from '../../mol-plugin-ui/controls/common';
|
||||
import { OpenInBrowserSvg } from '../../mol-plugin-ui/controls/icons';
|
||||
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { formatBytes } from '../../mol-util';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
|
||||
type ZenodoFile = {
|
||||
bucket: string
|
||||
checksum: string
|
||||
key: string
|
||||
links: {
|
||||
[key: string]: string
|
||||
self: string
|
||||
}
|
||||
size: number
|
||||
type: string
|
||||
}
|
||||
|
||||
type ZenodoRecord = {
|
||||
id: number
|
||||
conceptdoi: string
|
||||
conceptrecid: string
|
||||
created: string
|
||||
doi: string
|
||||
files: ZenodoFile[]
|
||||
revision: number
|
||||
updated: string
|
||||
metadata: {
|
||||
title: string
|
||||
}
|
||||
}
|
||||
|
||||
interface State {
|
||||
busy?: boolean
|
||||
recordValues: PD.Values<typeof ZenodoImportParams>
|
||||
importValues?: PD.Values<ImportParams>
|
||||
importParams?: ImportParams
|
||||
record?: ZenodoRecord
|
||||
files?: ZenodoFile[]
|
||||
}
|
||||
|
||||
const ZenodoImportParams = {
|
||||
record: PD.Text('', { description: 'Zenodo ID.' })
|
||||
};
|
||||
|
||||
function createImportParams(files: ZenodoFile[], plugin: PluginContext) {
|
||||
const modelOpts: [string, string][] = [];
|
||||
const topologyOpts: [string, string][] = [];
|
||||
const coordinatesOpts: [string, string][] = [];
|
||||
const volumeOpts: [string, string][] = [];
|
||||
const compressedOpts: [string, string][] = [];
|
||||
|
||||
const structureExts = new Map<string, { format: string, isBinary: boolean }>();
|
||||
const coordinatesExts = new Map<string, { format: string, isBinary: boolean }>();
|
||||
const topologyExts = new Map<string, { format: string, isBinary: boolean }>();
|
||||
const volumeExts = new Map<string, { format: string, isBinary: boolean }>();
|
||||
|
||||
for (const { provider: { category, binaryExtensions, stringExtensions }, name } of plugin.dataFormats.list) {
|
||||
if (category === TrajectoryFormatCategory) {
|
||||
if (binaryExtensions) for (const e of binaryExtensions) structureExts.set(e, { format: name, isBinary: true });
|
||||
if (stringExtensions) for (const e of stringExtensions) structureExts.set(e, { format: name, isBinary: false });
|
||||
} else if (category === VolumeFormatCategory) {
|
||||
if (binaryExtensions) for (const e of binaryExtensions) volumeExts.set(e, { format: name, isBinary: true });
|
||||
if (stringExtensions) for (const e of stringExtensions) volumeExts.set(e, { format: name, isBinary: false });
|
||||
} else if (category === CoordinatesFormatCategory) {
|
||||
if (binaryExtensions) for (const e of binaryExtensions) coordinatesExts.set(e, { format: name, isBinary: true });
|
||||
if (stringExtensions) for (const e of stringExtensions) coordinatesExts.set(e, { format: name, isBinary: false });
|
||||
} else if (category === TopologyFormatCategory) {
|
||||
if (binaryExtensions) for (const e of binaryExtensions) topologyExts.set(e, { format: name, isBinary: true });
|
||||
if (stringExtensions) for (const e of stringExtensions) topologyExts.set(e, { format: name, isBinary: false });
|
||||
}
|
||||
}
|
||||
|
||||
for (const file of files) {
|
||||
const label = `${file.key} (${formatBytes(file.size)})`;
|
||||
if (structureExts.has(file.type)) {
|
||||
const { format, isBinary } = structureExts.get(file.type)!;
|
||||
modelOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
|
||||
topologyOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
|
||||
} else if (volumeExts.has(file.type)) {
|
||||
const { format, isBinary } = volumeExts.get(file.type)!;
|
||||
volumeOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
|
||||
} else if (topologyExts.has(file.type)) {
|
||||
const { format, isBinary } = topologyExts.get(file.type)!;
|
||||
topologyOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
|
||||
} else if (coordinatesExts.has(file.type)) {
|
||||
const { format, isBinary } = coordinatesExts.get(file.type)!;
|
||||
coordinatesOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
|
||||
} else if (file.type === 'zip') {
|
||||
compressedOpts.push([`${file.links.self}|${file.type}|true`, label]);
|
||||
}
|
||||
}
|
||||
|
||||
const params: PD.Params = {};
|
||||
let defaultType = '';
|
||||
|
||||
if (modelOpts.length) {
|
||||
defaultType = 'structure';
|
||||
params.structure = PD.Select(modelOpts[0][0], modelOpts);
|
||||
}
|
||||
|
||||
if (topologyOpts.length && coordinatesOpts.length) {
|
||||
if (!defaultType) defaultType = 'trajectory';
|
||||
params.trajectory = PD.Group({
|
||||
topology: PD.Select(topologyOpts[0][0], topologyOpts),
|
||||
coordinates: PD.Select(coordinatesOpts[0][0], coordinatesOpts),
|
||||
}, { isFlat: true });
|
||||
}
|
||||
|
||||
if (volumeOpts.length) {
|
||||
if (!defaultType) defaultType = 'volume';
|
||||
params.volume = PD.Select(volumeOpts[0][0], volumeOpts);
|
||||
}
|
||||
|
||||
if (compressedOpts.length) {
|
||||
if (!defaultType) defaultType = 'compressed';
|
||||
params.compressed = PD.Select(compressedOpts[0][0], compressedOpts);
|
||||
}
|
||||
|
||||
return {
|
||||
type: PD.MappedStatic(defaultType, Object.keys(params).length ? params : { '': PD.EmptyGroup() })
|
||||
};
|
||||
}
|
||||
type ImportParams = ReturnType<typeof createImportParams>
|
||||
|
||||
export class ZenodoImportUI extends CollapsableControls<{}, State> {
|
||||
protected defaultState(): State & CollapsableState {
|
||||
return {
|
||||
header: 'Zenodo Import',
|
||||
isCollapsed: true,
|
||||
brand: { accent: 'cyan', svg: OpenInBrowserSvg },
|
||||
recordValues: PD.getDefaultValues(ZenodoImportParams),
|
||||
importValues: undefined,
|
||||
importParams: undefined,
|
||||
record: undefined,
|
||||
files: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private recordParamsOnChange = (values: any) => {
|
||||
this.setState({ recordValues: values });
|
||||
};
|
||||
|
||||
private importParamsOnChange = (values: any) => {
|
||||
this.setState({ importValues: values });
|
||||
};
|
||||
|
||||
private loadRecord = async () => {
|
||||
try {
|
||||
this.setState({ busy: true });
|
||||
const record: ZenodoRecord = await this.plugin.runTask(this.plugin.fetch({ url: `https://zenodo.org/api/records/${this.state.recordValues.record}`, type: 'json' }));
|
||||
const importParams = createImportParams(record.files, this.plugin);
|
||||
this.setState({
|
||||
record,
|
||||
files: record.files,
|
||||
busy: false,
|
||||
importValues: PD.getDefaultValues(importParams),
|
||||
importParams
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this.plugin.log.error(`Failed to load Zenodo record '${this.state.recordValues.record}'`);
|
||||
this.setState({ busy: false });
|
||||
}
|
||||
};
|
||||
|
||||
private loadFile = async (values: PD.Values<ImportParams>) => {
|
||||
try {
|
||||
this.setState({ busy: true });
|
||||
|
||||
const t = values.type;
|
||||
if (t.name === 'structure') {
|
||||
const defaultParams = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
|
||||
const [url, format, isBinary] = t.params.split('|');
|
||||
|
||||
await this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
name: 'url',
|
||||
params: {
|
||||
url,
|
||||
format: format as any,
|
||||
isBinary: isBinary === 'true',
|
||||
options: defaultParams.source.params.options,
|
||||
}
|
||||
}
|
||||
}));
|
||||
} else if (t.name === 'trajectory') {
|
||||
const [topologyUrl, topologyFormat, topologyIsBinary] = t.params.topology.split('|');
|
||||
const [coordinatesUrl, coordinatesFormat, coordinatesIsBinary] = t.params.coordinates.split('|');
|
||||
|
||||
await this.plugin.runTask(this.plugin.state.data.applyAction(LoadTrajectory, {
|
||||
source: {
|
||||
name: 'url',
|
||||
params: {
|
||||
model: {
|
||||
url: topologyUrl,
|
||||
format: topologyFormat as any,
|
||||
isBinary: topologyIsBinary === 'true',
|
||||
},
|
||||
coordinates: {
|
||||
url: coordinatesUrl,
|
||||
format: coordinatesFormat as any,
|
||||
isBinary: coordinatesIsBinary === 'true',
|
||||
},
|
||||
}
|
||||
}
|
||||
}));
|
||||
} else if (t.name === 'volume') {
|
||||
const [url, format, isBinary] = t.params.split('|');
|
||||
|
||||
await this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
|
||||
source: {
|
||||
name: 'url',
|
||||
params: {
|
||||
url,
|
||||
format: format as any,
|
||||
isBinary: isBinary === 'true',
|
||||
}
|
||||
}
|
||||
}));
|
||||
} else if (t.name === 'compressed') {
|
||||
const [url, format, isBinary] = t.params.split('|');
|
||||
|
||||
await this.plugin.runTask(this.plugin.state.data.applyAction(DownloadFile, {
|
||||
url,
|
||||
format: format as any,
|
||||
isBinary: isBinary === 'true',
|
||||
visuals: true
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this.plugin.log.error(`Failed to load Zenodo file`);
|
||||
} finally {
|
||||
this.setState({ busy: false });
|
||||
}
|
||||
};
|
||||
|
||||
private clearRecord = () => {
|
||||
this.setState({
|
||||
importValues: undefined,
|
||||
importParams: undefined,
|
||||
record: undefined,
|
||||
files: undefined
|
||||
});
|
||||
};
|
||||
|
||||
private renderLoadRecord() {
|
||||
return <div style={{ marginBottom: 10 }}>
|
||||
<ParameterControls params={ZenodoImportParams} values={this.state.recordValues} onChangeValues={this.recordParamsOnChange} isDisabled={this.state.busy} />
|
||||
<Button onClick={this.loadRecord} style={{ marginTop: 1 }} disabled={this.state.busy || !this.state.recordValues.record}>
|
||||
Load Record
|
||||
</Button>
|
||||
</div>;
|
||||
}
|
||||
|
||||
private renderRecordInfo(record: ZenodoRecord) {
|
||||
return <div style={{ marginBottom: 10 }}>
|
||||
<div className='msp-help-text'>
|
||||
<div>Record {`${record.id}`}: <i>{`${record.metadata.title}`}</i></div>
|
||||
</div>
|
||||
<Button onClick={this.clearRecord} style={{ marginTop: 1 }} disabled={this.state.busy}>
|
||||
Clear
|
||||
</Button>
|
||||
</div>;
|
||||
}
|
||||
|
||||
private renderImportFile(params: ImportParams, values: PD.Values<ImportParams>) {
|
||||
return values.type.name ? <div style={{ marginBottom: 10 }}>
|
||||
<ParameterControls params={params} values={this.state.importValues} onChangeValues={this.importParamsOnChange} isDisabled={this.state.busy} />
|
||||
<Button onClick={() => this.loadFile(values)} style={{ marginTop: 1 }} disabled={this.state.busy}>
|
||||
Import File
|
||||
</Button>
|
||||
</div> : <div className='msp-help-text' style={{ marginBottom: 10 }}>
|
||||
<div>No supported files</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
protected renderControls(): JSX.Element | null {
|
||||
return <>
|
||||
{!this.state.record ? this.renderLoadRecord() : null}
|
||||
{this.state.record ? this.renderRecordInfo(this.state.record) : null}
|
||||
{this.state.importParams && this.state.importValues ? this.renderImportFile(this.state.importParams, this.state.importValues) : null}
|
||||
</>;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { Viewport, cameraProject, cameraUnproject } from './camera/util';
|
||||
import { CameraTransitionManager } from './camera/transition';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { Scene } from '../mol-gl/scene';
|
||||
import { assertUnreachable } from '../mol-util/type-helpers';
|
||||
|
||||
export { ICamera, Camera };
|
||||
|
||||
@@ -84,7 +85,7 @@ class Camera implements ICamera {
|
||||
switch (this.state.mode) {
|
||||
case 'orthographic': updateOrtho(this); break;
|
||||
case 'perspective': updatePers(this); break;
|
||||
default: throw new Error('unknown camera mode');
|
||||
default: assertUnreachable(this.state.mode);
|
||||
}
|
||||
|
||||
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON) || !Mat4.areEqual(this.view, this.prevView, EPSILON);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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>
|
||||
@@ -61,6 +61,29 @@ describe('column', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('string column', () => {
|
||||
const xs = ['A', 'b', null, undefined];
|
||||
const xsArr = xs.map(x => x ?? '');
|
||||
const xsLC = xs.map(x => (x ?? '').toLowerCase());
|
||||
const arr = Column.ofArray({ array: xs as any, schema: Column.Schema.str });
|
||||
const arrLC = Column.ofArray({ array: xs as any, schema: Column.Schema.Str({ transform: 'lowercase' }) });
|
||||
const aliasedLC = Column.ofArray({ array: xs as any, schema: Column.Schema.Aliased<'a' | 'b'>(Column.Schema.lstr) });
|
||||
|
||||
it('value', () => {
|
||||
for (let i = 0; i < xs.length; i++) {
|
||||
expect(arr.value(i)).toBe(xs[i] ?? '');
|
||||
expect(arrLC.value(i)).toBe(xsLC[i] ?? '');
|
||||
expect(aliasedLC.value(i)).toBe(xsLC[i]);
|
||||
}
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
expect(arr.toArray()).toEqual(xsArr);
|
||||
expect(arrLC.toArray()).toEqual(xsLC);
|
||||
expect(aliasedLC.toArray()).toEqual(xsLC);
|
||||
});
|
||||
});
|
||||
|
||||
describe('table', () => {
|
||||
const schema = {
|
||||
x: Column.Schema.int,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -25,38 +25,39 @@ interface Column<T> {
|
||||
namespace Column {
|
||||
export type ArrayCtor<T> = { new(size: number): ArrayLike<T> }
|
||||
|
||||
export type Schema<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T> | Schema.Tensor | Schema.List<number|string>
|
||||
export type Schema<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T> | Schema.Tensor | Schema.List<number | string>
|
||||
|
||||
export namespace Schema {
|
||||
// T also serves as a default value for undefined columns
|
||||
|
||||
type Base<T extends string> = { valueType: T }
|
||||
export type Str = { '@type': 'str', T: string } & Base<'str'>
|
||||
export type Str = { '@type': 'str', T: string, transform?: 'uppercase' | 'lowercase' } & Base<'str'>
|
||||
export type Int = { '@type': 'int', T: number } & Base<'int'>
|
||||
export type Float = { '@type': 'float', T: number } & Base<'float'>
|
||||
export type Coordinate = { '@type': 'coord', T: number } & Base<'float'>
|
||||
|
||||
export type Tensor = { '@type': 'tensor', T: Tensors.Data, space: Tensors.Space, baseType: Int | Float } & Base<'tensor'>
|
||||
export type Aliased<T> = { '@type': 'aliased', T: T } & Base<T extends string ? 'str' : 'int'>
|
||||
export type List<T extends number|string> = { '@type': 'list', T: T[], separator: string, itemParse: (x: string) => T } & Base<'list'>
|
||||
export type Aliased<T> = { '@type': 'aliased', T: T, transform?: T extends string ? 'uppercase' | 'lowercase' : never } & Base<T extends string ? 'str' : 'int'>
|
||||
export type List<T extends number | string> = { '@type': 'list', T: T[], separator: string, itemParse: (x: string) => T } & Base<'list'>
|
||||
|
||||
export const str: Str = { '@type': 'str', T: '', valueType: 'str' };
|
||||
export const ustr: Str = { '@type': 'str', T: '', valueType: 'str', transform: 'uppercase' };
|
||||
export const lstr: Str = { '@type': 'str', T: '', valueType: 'str', transform: 'lowercase' };
|
||||
export const int: Int = { '@type': 'int', T: 0, valueType: 'int' };
|
||||
export const coord: Coordinate = { '@type': 'coord', T: 0, valueType: 'float' };
|
||||
export const float: Float = { '@type': 'float', T: 0, valueType: 'float' };
|
||||
|
||||
export function Str(defaultValue = ''): Str { return { '@type': 'str', T: defaultValue, valueType: 'str' }; };
|
||||
export function Str(options?: { defaultValue?: string, transform?: 'uppercase' | 'lowercase' }): Str { return { '@type': 'str', T: options?.defaultValue ?? '', transform: options?.transform, valueType: 'str' }; };
|
||||
export function Int(defaultValue = 0): Int { return { '@type': 'int', T: defaultValue, valueType: 'int' }; };
|
||||
export function Float(defaultValue = 0): Float { return { '@type': 'float', T: defaultValue, valueType: 'float' }; };
|
||||
export function Tensor(space: Tensors.Space, baseType: Int | Float = float): Tensor { return { '@type': 'tensor', T: space.create(), space, valueType: 'tensor', baseType }; }
|
||||
export function Vector(dim: number, baseType: Int | Float = float): Tensor { return Tensor(Tensors.Vector(dim, baseType['@type'] === 'int' ? Int32Array : Float64Array), baseType); }
|
||||
export function Matrix(rows: number, cols: number, baseType: Int | Float = float): Tensor { return Tensor(Tensors.ColumnMajorMatrix(rows, cols, baseType['@type'] === 'int' ? Int32Array : Float64Array), baseType); }
|
||||
|
||||
export function Aliased<T>(t: Str | Int, defaultValue?: T): Aliased<T> {
|
||||
if (typeof defaultValue !== 'undefined') return { ...t, T: defaultValue } as any as Aliased<T>;
|
||||
export function Aliased<T>(t: Str | Int): Aliased<T> {
|
||||
return t as any as Aliased<T>;
|
||||
}
|
||||
export function List<T extends number|string>(separator: string, itemParse: (x: string) => T, defaultValue: T[] = []): List<T> {
|
||||
export function List<T extends number | string>(separator: string, itemParse: (x: string) => T, defaultValue: T[] = []): List<T> {
|
||||
return { '@type': 'list', T: defaultValue, separator, itemParse, valueType: 'list' };
|
||||
}
|
||||
}
|
||||
@@ -287,8 +288,13 @@ function lambdaColumn<T extends Column.Schema>({ value, valueKind, areValuesEqua
|
||||
|
||||
function arrayColumn<T extends Column.Schema>({ array, schema, valueKind }: Column.ArraySpec<T>): Column<T['T']> {
|
||||
const rowCount = array.length;
|
||||
const defaultValue = schema.T;
|
||||
const value: Column<T['T']>['value'] = schema.valueType === 'str'
|
||||
? row => { const v = array[row]; return typeof v === 'string' ? v : '' + v; }
|
||||
? (schema as Column.Schema.Str).transform === 'lowercase'
|
||||
? row => { const v = array[row]; return typeof v === 'string' ? v.toLowerCase() : `${v ?? defaultValue}`.toLowerCase(); }
|
||||
: (schema as Column.Schema.Str).transform === 'uppercase'
|
||||
? row => { const v = array[row]; return typeof v === 'string' ? v.toUpperCase() : `${v ?? defaultValue}`.toUpperCase(); }
|
||||
: row => { const v = array[row]; return typeof v === 'string' ? v : `${v ?? defaultValue}`; }
|
||||
: row => array[row];
|
||||
|
||||
const isTyped = ColumnHelpers.isTypedArray(array);
|
||||
@@ -300,15 +306,35 @@ function arrayColumn<T extends Column.Schema>({ array, schema, valueKind }: Colu
|
||||
value,
|
||||
valueKind: valueKind ? valueKind : row => Column.ValueKind.Present,
|
||||
toArray: schema.valueType === 'str'
|
||||
? params => {
|
||||
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
|
||||
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
|
||||
for (let i = 0, _i = end - start; i < _i; i++) {
|
||||
const v = array[start + i];
|
||||
ret[i] = typeof v === 'string' ? v : '' + v;
|
||||
? (schema as Column.Schema.Str).transform === 'lowercase'
|
||||
? params => {
|
||||
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
|
||||
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
|
||||
for (let i = 0, _i = end - start; i < _i; i++) {
|
||||
const v = array[start + i];
|
||||
ret[i] = typeof v === 'string' ? v.toLowerCase() : `${v ?? defaultValue}`.toLowerCase();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
: (schema as Column.Schema.Str).transform === 'uppercase'
|
||||
? params => {
|
||||
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
|
||||
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
|
||||
for (let i = 0, _i = end - start; i < _i; i++) {
|
||||
const v = array[start + i];
|
||||
ret[i] = typeof v === 'string' ? v.toUpperCase() : `${v ?? defaultValue}`.toUpperCase();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
: params => {
|
||||
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
|
||||
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
|
||||
for (let i = 0, _i = end - start; i < _i; i++) {
|
||||
const v = array[start + i];
|
||||
ret[i] = typeof v === 'string' ? v : `${v ?? defaultValue}`;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
: isTyped
|
||||
? params => ColumnHelpers.typedArrayWindow(array, params) as any as ReadonlyArray<T>
|
||||
: params => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -157,6 +157,7 @@ export namespace Cylinders {
|
||||
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
allowTransparentBackfaces: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2021-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -34,13 +34,15 @@ export function calcMeshColorSmoothing(input: ColorSmoothingInput, resolution: n
|
||||
|
||||
const isInstanceType = colorType.endsWith('Instance');
|
||||
const box = Box3D.fromSphere3D(Box3D(), isInstanceType ? input.boundingSphere : input.invariantBoundingSphere);
|
||||
const pad = 1 + resolution;
|
||||
const expandedBox = Box3D.expand(Box3D(), box, Vec3.create(pad, pad, pad));
|
||||
|
||||
const scaleFactor = 1 / resolution;
|
||||
const scaledBox = Box3D.scale(Box3D(), box, scaleFactor);
|
||||
const scaledBox = Box3D.scale(Box3D(), expandedBox, scaleFactor);
|
||||
const gridDim = Box3D.size(Vec3(), scaledBox);
|
||||
Vec3.ceil(gridDim, gridDim);
|
||||
Vec3.add(gridDim, gridDim, Vec3.create(2, 2, 2));
|
||||
const { min } = box;
|
||||
const { min } = expandedBox;
|
||||
|
||||
const [xn, yn] = gridDim;
|
||||
const { width, height } = getVolumeTexture2dLayout(gridDim);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
@@ -625,6 +625,7 @@ export namespace Mesh {
|
||||
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
allowTransparentBackfaces: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -129,6 +129,7 @@ export namespace Spheres {
|
||||
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
allowTransparentBackfaces: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { ChunkedArray } from '../../../mol-data/util';
|
||||
import { Text } from './text';
|
||||
import { getFontAtlas } from './font-atlas';
|
||||
import { assertUnreachable } from '../../../mol-util/type-helpers';
|
||||
|
||||
const quadIndices = new Uint16Array([
|
||||
0, 1, 2,
|
||||
@@ -237,7 +238,7 @@ export namespace TextBuilder {
|
||||
yBaseCenter = yTop;
|
||||
break;
|
||||
default:
|
||||
throw new Error('unsupported attachment');
|
||||
assertUnreachable(attachment);
|
||||
}
|
||||
caAdd2(mappings, xTip, yTip); // tip
|
||||
caAdd2(mappings, xBaseA, yBaseA); // base A
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2021-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -259,13 +259,15 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
|
||||
|
||||
const isInstanceType = input.colorType.endsWith('Instance');
|
||||
const box = Box3D.fromSphere3D(Box3D(), isInstanceType ? input.boundingSphere : input.invariantBoundingSphere);
|
||||
const pad = 1 + resolution;
|
||||
const expandedBox = Box3D.expand(Box3D(), box, Vec3.create(pad, pad, pad));
|
||||
|
||||
const scaleFactor = 1 / resolution;
|
||||
const scaledBox = Box3D.scale(Box3D(), box, scaleFactor);
|
||||
const scaledBox = Box3D.scale(Box3D(), expandedBox, scaleFactor);
|
||||
const gridDim = Box3D.size(Vec3(), scaledBox);
|
||||
Vec3.ceil(gridDim, gridDim);
|
||||
Vec3.add(gridDim, gridDim, Vec3.create(2, 2, 2));
|
||||
const { min } = box;
|
||||
const { min } = expandedBox;
|
||||
|
||||
const [dx, dy, dz] = gridDim;
|
||||
const { texDimX: width, texDimY: height, texCols } = getTexture2dSize(gridDim);
|
||||
@@ -308,7 +310,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
|
||||
accumulateTexture.attachFramebuffer(framebuffer, 0);
|
||||
countTexture.attachFramebuffer(framebuffer, 1);
|
||||
|
||||
const accumulateRenderable = getAccumulateRenderable(webgl, input, box, resolution, stride);
|
||||
const accumulateRenderable = getAccumulateRenderable(webgl, input, expandedBox, resolution, stride);
|
||||
state.currentRenderItemId = -1;
|
||||
|
||||
framebuffer.bind();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -113,6 +113,7 @@ export namespace TextureMesh {
|
||||
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
allowTransparentBackfaces: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
|
||||
@@ -202,6 +202,7 @@ export const DirectVolumeShaderCode = ShaderCode('direct-volume', directVolume_v
|
||||
|
||||
import { image_vert } from './shader/image.vert';
|
||||
import { image_frag } from './shader/image.frag';
|
||||
import { assertUnreachable } from '../mol-util/type-helpers';
|
||||
export const ImageShaderCode = ShaderCode('image', image_vert, image_frag, { drawBuffers: 'optional' }, {}, ignoreDefineUnlit);
|
||||
|
||||
//
|
||||
@@ -228,7 +229,7 @@ function getDefinesCode(defines: ShaderDefines, ignore?: IgnoreDefine) {
|
||||
} else if (typeof v === 'boolean') {
|
||||
if (v) lines.push(`#define ${name}`);
|
||||
} else {
|
||||
throw new Error('unknown define type');
|
||||
assertUnreachable(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
@@ -13,7 +13,7 @@ export const wboit_write = `
|
||||
}
|
||||
} else if (uRenderWboit) {
|
||||
// the 'fragmentDepth > 0.99' check is to handle precision issues with packed depth
|
||||
if (preFogAlpha != 1.0 && !interior && (fragmentDepth < getDepth(gl_FragCoord.xy / uDrawingBufferSize) || fragmentDepth > 0.99)) {
|
||||
if (preFogAlpha != 1.0 && (fragmentDepth < getDepth(gl_FragCoord.xy / uDrawingBufferSize) || fragmentDepth > 0.99)) {
|
||||
float alpha = gl_FragColor.a;
|
||||
float wboitWeight = alpha * clamp(pow(1.0 - fragmentDepth, 2.0), 0.01, 1.0);
|
||||
gl_FragColor = vec4(gl_FragColor.rgb * alpha * wboitWeight, alpha);
|
||||
|
||||
@@ -72,12 +72,7 @@ uniform float uPickingAlphaThreshold;
|
||||
uniform bool uTransparentBackground;
|
||||
uniform float uXrayEdgeFalloff;
|
||||
|
||||
uniform float uInteriorDarkening;
|
||||
uniform bool uInteriorColorFlag;
|
||||
uniform vec3 uInteriorColor;
|
||||
|
||||
uniform bool uRenderWboit;
|
||||
uniform bool uDoubleSided;
|
||||
|
||||
uniform float uNear;
|
||||
uniform float uFar;
|
||||
@@ -357,7 +352,6 @@ void main() {
|
||||
|
||||
float fragmentDepth = calcDepth((uModelView * vec4(start, 1.0)).xyz);
|
||||
float preFogAlpha = clamp(preFogAlphaBlended, 0.0, 1.0);
|
||||
bool interior = false;
|
||||
#include wboit_write
|
||||
}
|
||||
`;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -99,7 +99,6 @@ void main() {
|
||||
if (imageData.a > 0.9) imageData.a = 1.0;
|
||||
|
||||
float fragmentDepth = gl_FragCoord.z;
|
||||
bool interior = false;
|
||||
|
||||
#if defined(dRenderVariant_pick)
|
||||
if (imageData.a < 0.3)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -16,7 +16,6 @@ precision highp int;
|
||||
void main(){
|
||||
#include clip_pixel
|
||||
|
||||
bool interior = false;
|
||||
float fragmentDepth = gl_FragCoord.z;
|
||||
#include assign_material_color
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -20,7 +20,6 @@ void main(){
|
||||
#include clip_pixel
|
||||
|
||||
float fragmentDepth = gl_FragCoord.z;
|
||||
bool interior = false;
|
||||
#include assign_material_color
|
||||
|
||||
#if defined(dPointStyle_circle)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -33,7 +33,6 @@ void main(){
|
||||
#include clip_pixel
|
||||
|
||||
float fragmentDepth = gl_FragCoord.z;
|
||||
bool interior = false;
|
||||
#include assign_material_color
|
||||
|
||||
if (vTexCoord.x > 1.0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -8,8 +8,8 @@ import { WebGLContext } from './context';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
import { RenderableSchema } from '../renderable/schema';
|
||||
import { idFactory } from '../../mol-util/id-factory';
|
||||
import { ValueOf } from '../../mol-util/type-helpers';
|
||||
import { GLRenderingContext } from './compat';
|
||||
import { assertUnreachable, ValueOf } from '../../mol-util/type-helpers';
|
||||
import { GLRenderingContext, isWebGL2 } from './compat';
|
||||
import { WebGLExtensions } from './extensions';
|
||||
import { WebGLState } from './state';
|
||||
|
||||
@@ -48,6 +48,7 @@ export function getDataType(gl: GLRenderingContext, dataType: DataType) {
|
||||
case 'uint32': return gl.UNSIGNED_INT;
|
||||
case 'int32': return gl.INT;
|
||||
case 'float32': return gl.FLOAT;
|
||||
default: assertUnreachable(dataType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,16 +67,20 @@ function dataTypeFromArray(gl: GLRenderingContext, array: ArrayType) {
|
||||
return gl.INT;
|
||||
} else if (array instanceof Float32Array) {
|
||||
return gl.FLOAT;
|
||||
} else {
|
||||
throw new Error('Should nevver happen');
|
||||
}
|
||||
assertUnreachable(array);
|
||||
}
|
||||
|
||||
export function getBufferType(gl: GLRenderingContext, bufferType: BufferType) {
|
||||
switch (bufferType) {
|
||||
case 'attribute': return gl.ARRAY_BUFFER;
|
||||
case 'elements': return gl.ELEMENT_ARRAY_BUFFER;
|
||||
case 'uniform': return (gl as WebGL2RenderingContext).UNIFORM_BUFFER;
|
||||
case 'uniform':
|
||||
if (isWebGL2(gl)) {
|
||||
return gl.UNIFORM_BUFFER;
|
||||
} else {
|
||||
throw new Error('WebGL2 is required for uniform buffers');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,18 +163,10 @@ function createBuffer(gl: GLRenderingContext, array: ArrayType, usageHint: Usage
|
||||
//
|
||||
|
||||
export type AttributeItemSize = 1 | 2 | 3 | 4 | 16
|
||||
export type AttributeKind = 'float32' | 'int32'
|
||||
export type AttributeKind = 'float32'
|
||||
|
||||
export function getAttribType(gl: GLRenderingContext, kind: AttributeKind, itemSize: AttributeItemSize) {
|
||||
switch (kind) {
|
||||
case 'int32':
|
||||
switch (itemSize) {
|
||||
case 1: return gl.INT;
|
||||
case 2: return gl.INT_VEC2;
|
||||
case 3: return gl.INT_VEC3;
|
||||
case 4: return gl.INT_VEC4;
|
||||
}
|
||||
break;
|
||||
case 'float32':
|
||||
switch (itemSize) {
|
||||
case 1: return gl.FLOAT;
|
||||
@@ -178,9 +175,9 @@ export function getAttribType(gl: GLRenderingContext, kind: AttributeKind, itemS
|
||||
case 4: return gl.FLOAT_VEC4;
|
||||
case 16: return gl.FLOAT_MAT4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assertUnreachable(kind);
|
||||
}
|
||||
throw new Error(`unknown attribute type for kind '${kind}' and itemSize '${itemSize}'`);
|
||||
}
|
||||
|
||||
export type AttributeDefs = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -281,7 +281,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal
|
||||
gl,
|
||||
isWebGL2: isWebGL2(gl),
|
||||
get pixelRatio() {
|
||||
const dpr = (typeof window !== 'undefined') ? window.devicePixelRatio : 1;
|
||||
const dpr = (typeof window !== 'undefined') ? (window.devicePixelRatio || 1) : 1;
|
||||
return dpr * (props.pixelScale || 1);
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -13,7 +13,7 @@ import { TextureId, Textures } from './texture';
|
||||
import { idFactory } from '../../mol-util/id-factory';
|
||||
import { RenderableSchema } from '../renderable/schema';
|
||||
import { isDebugMode } from '../../mol-util/debug';
|
||||
import { GLRenderingContext } from './compat';
|
||||
import { GLRenderingContext, isWebGL2 } from './compat';
|
||||
import { ShaderType, Shader } from './shader';
|
||||
|
||||
const getNextProgramId = idFactory();
|
||||
@@ -72,7 +72,7 @@ function checkActiveAttributes(gl: GLRenderingContext, program: WebGLProgram, sc
|
||||
}
|
||||
const attribType = getAttribType(gl, spec.kind, spec.itemSize);
|
||||
if (attribType !== type) {
|
||||
throw new Error(`unexpected attribute type for ${name}`);
|
||||
throw new Error(`unexpected attribute type '${attribType}' for ${name}, expected '${type}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,8 +104,12 @@ function checkActiveUniforms(gl: GLRenderingContext, program: WebGLProgram, sche
|
||||
throw new Error(`unexpected sampler type for '${name}'`);
|
||||
}
|
||||
} else if (spec.kind === 'volume-float32' || spec.kind === 'volume-uint8') {
|
||||
if (type !== (gl as WebGL2RenderingContext).SAMPLER_3D) {
|
||||
throw new Error(`unexpected sampler type for '${name}'`);
|
||||
if (isWebGL2(gl)) {
|
||||
if (type !== gl.SAMPLER_3D) {
|
||||
throw new Error(`unexpected sampler type for '${name}'`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`WebGL2 is required to use SAMPLER_3D`);
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import { ArrayEncoder, ArrayEncoding as E } from './array-encoder';
|
||||
import { getArrayDigitCount } from '../../../mol-util/number';
|
||||
import { assertUnreachable } from '../../../mol-util/type-helpers';
|
||||
|
||||
export function classifyIntArray(xs: ArrayLike<number>) {
|
||||
return IntClassifier.classify(xs as number[]);
|
||||
@@ -62,7 +63,7 @@ namespace IntClassifier {
|
||||
for (let i = 0, n = data.length; i < n; i++) {
|
||||
incSize(info, size, data[i]);
|
||||
}
|
||||
return { ...byteSize(size), kind: 'pack' };
|
||||
return { ...byteSize(size), kind: 'pack' as const };
|
||||
}
|
||||
|
||||
function deltaSize(data: number[], info: IntColumnInfo) {
|
||||
@@ -72,7 +73,7 @@ namespace IntClassifier {
|
||||
incSizeSigned(size, data[i] - prev);
|
||||
prev = data[i];
|
||||
}
|
||||
return { ...byteSize(size), kind: 'delta' };
|
||||
return { ...byteSize(size), kind: 'delta' as const };
|
||||
}
|
||||
|
||||
function rleSize(data: number[], info: IntColumnInfo) {
|
||||
@@ -90,7 +91,7 @@ namespace IntClassifier {
|
||||
incSize(info, size, data[data.length - 1]);
|
||||
incSize(info, size, run);
|
||||
|
||||
return { ...byteSize(size), kind: 'rle' };
|
||||
return { ...byteSize(size), kind: 'rle' as const };
|
||||
}
|
||||
|
||||
function deltaRleSize(data: number[], info: IntColumnInfo) {
|
||||
@@ -111,7 +112,7 @@ namespace IntClassifier {
|
||||
incSizeSigned(size, prevValue);
|
||||
incSizeSigned(size, run);
|
||||
|
||||
return { ...byteSize(size), kind: 'delta-rle' };
|
||||
return { ...byteSize(size), kind: 'delta-rle' as const };
|
||||
}
|
||||
|
||||
export function getSize(data: number[]) {
|
||||
@@ -132,9 +133,8 @@ namespace IntClassifier {
|
||||
case 'rle': return E.by(E.runLength).and(E.integerPacking);
|
||||
case 'delta': return E.by(E.delta).and(E.integerPacking);
|
||||
case 'delta-rle': return E.by(E.delta).and(E.runLength).and(E.integerPacking);
|
||||
default: assertUnreachable(size);
|
||||
}
|
||||
|
||||
throw new Error('should not happen :)');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,9 +169,8 @@ namespace FloatClassifier {
|
||||
case 'rle': return fp.and(E.runLength).and(E.integerPacking);
|
||||
case 'delta': return fp.and(E.delta).and(E.integerPacking);
|
||||
case 'delta-rle': return fp.and(E.delta).and(E.runLength).and(E.integerPacking);
|
||||
default: assertUnreachable(size);
|
||||
}
|
||||
|
||||
throw new Error('should not happen :)');
|
||||
}
|
||||
|
||||
function getMultiplier(mantissaDigits: number) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import { Encoding, EncodedData } from './encoding';
|
||||
import { IsNativeEndianLittle, flipByteOrder } from '../binary';
|
||||
import { assertUnreachable } from '../../../mol-util/type-helpers';
|
||||
|
||||
/**
|
||||
* Fixed point, delta, RLE, integer packing adopted from https://github.com/rcsb/mmtf-javascript/
|
||||
@@ -33,7 +34,7 @@ function decodeStep(data: any, encoding: Encoding): any {
|
||||
case Encoding.IntDataType.Uint32: return uint32(data);
|
||||
case Encoding.FloatDataType.Float32: return float32(data);
|
||||
case Encoding.FloatDataType.Float64: return float64(data);
|
||||
default: throw new Error('Unsupported ByteArray type.');
|
||||
default: assertUnreachable(encoding.type);
|
||||
}
|
||||
}
|
||||
case 'FixedPoint': return fixedPoint(data, encoding);
|
||||
@@ -53,7 +54,7 @@ function getIntArray(type: Encoding.IntDataType, size: number) {
|
||||
case Encoding.IntDataType.Uint8: return new Uint8Array(size);
|
||||
case Encoding.IntDataType.Uint16: return new Uint16Array(size);
|
||||
case Encoding.IntDataType.Uint32: return new Uint32Array(size);
|
||||
default: throw new Error('Unsupported integer data type.');
|
||||
default: assertUnreachable(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +62,7 @@ function getFloatArray(type: Encoding.FloatDataType, size: number) {
|
||||
switch (type) {
|
||||
case Encoding.FloatDataType.Float32: return new Float32Array(size);
|
||||
case Encoding.FloatDataType.Float64: return new Float64Array(size);
|
||||
default: throw new Error('Unsupported floating data type.');
|
||||
default: assertUnreachable(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
453
src/mol-io/common/io-buffer.ts
Normal file
453
src/mol-io/common/io-buffer.ts
Normal file
@@ -0,0 +1,453 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Adapted and converted to TypeScript from https://github.com/image-js/iobuffer
|
||||
* MIT License, Copyright (c) 2015 Michaël Zasso
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { TypedArray } from '../../mol-util/type-helpers';
|
||||
|
||||
const defaultByteLength = 1024 * 8;
|
||||
const charArray: string[] = [];
|
||||
|
||||
export interface IOBufferParameters {
|
||||
offset?: number // Ignore the first n bytes of the ArrayBuffer
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for writing and reading binary data
|
||||
*/
|
||||
export class IOBuffer {
|
||||
private _lastWrittenByte: number;
|
||||
private _mark = 0;
|
||||
private _marks: number[] = [];
|
||||
private _data: DataView;
|
||||
|
||||
offset = 0; // The current offset of the buffer's pointer
|
||||
littleEndian = true;
|
||||
buffer: ArrayBuffer; // Reference to the internal ArrayBuffer object
|
||||
length: number; // Byte length of the internal ArrayBuffer
|
||||
byteLength: number; // Byte length of the internal ArrayBuffer
|
||||
byteOffset: number; // Byte offset of the internal ArrayBuffer
|
||||
|
||||
/**
|
||||
* If it's a number, it will initialize the buffer with the number as
|
||||
* the buffer's length. If it's undefined, it will initialize the buffer
|
||||
* with a default length of 8 Kb. If its an ArrayBuffer, a TypedArray,
|
||||
* it will create a view over the underlying ArrayBuffer.
|
||||
*/
|
||||
constructor(data: number | ArrayBuffer | TypedArray, params: IOBufferParameters = {}) {
|
||||
let dataIsGiven = false;
|
||||
if (data === undefined) {
|
||||
data = defaultByteLength;
|
||||
}
|
||||
if (typeof data === 'number') {
|
||||
data = new ArrayBuffer(data);
|
||||
} else {
|
||||
dataIsGiven = true;
|
||||
}
|
||||
|
||||
const offset = params.offset ? params.offset >>> 0 : 0;
|
||||
const byteLength = data.byteLength - offset;
|
||||
let dvOffset = offset;
|
||||
if (!(data instanceof ArrayBuffer)) {
|
||||
if (data.byteLength !== data.buffer.byteLength) {
|
||||
dvOffset = data.byteOffset + offset;
|
||||
}
|
||||
data = data.buffer;
|
||||
}
|
||||
if (dataIsGiven) {
|
||||
this._lastWrittenByte = byteLength;
|
||||
} else {
|
||||
this._lastWrittenByte = 0;
|
||||
}
|
||||
|
||||
this.buffer = data;
|
||||
this.length = byteLength;
|
||||
this.byteLength = byteLength;
|
||||
this.byteOffset = dvOffset;
|
||||
|
||||
this._data = new DataView(this.buffer, dvOffset, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the memory allocated to the buffer is sufficient to store more bytes after the offset
|
||||
* @param byteLength The needed memory in bytes
|
||||
*/
|
||||
available(byteLength: number = 1) {
|
||||
return (this.offset + byteLength) <= this.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if little-endian mode is used for reading and writing multi-byte values
|
||||
* Returns true if little-endian mode is used, false otherwise
|
||||
*/
|
||||
isLittleEndian() {
|
||||
return this.littleEndian;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set little-endian mode for reading and writing multi-byte values
|
||||
*/
|
||||
setLittleEndian() {
|
||||
this.littleEndian = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if big-endian mode is used for reading and writing multi-byte values
|
||||
* Returns true if big-endian mode is used, false otherwise
|
||||
*/
|
||||
isBigEndian() {
|
||||
return !this.littleEndian;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to big-endian mode for reading and writing multi-byte values
|
||||
*/
|
||||
setBigEndian() {
|
||||
this.littleEndian = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer n bytes forward
|
||||
*/
|
||||
skip(n: number) {
|
||||
if (n === undefined) n = 1;
|
||||
this.offset += n;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer to the given offset
|
||||
*/
|
||||
seek(offset: number) {
|
||||
this.offset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the current pointer offset.
|
||||
*/
|
||||
mark() {
|
||||
this._mark = this.offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer back to the last pointer offset set by mark
|
||||
*/
|
||||
reset() {
|
||||
this.offset = this._mark;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the current pointer offset to the mark stack
|
||||
*/
|
||||
pushMark() {
|
||||
this._marks.push(this.offset);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the last pointer offset from the mark stack, and set the current pointer offset to the popped value
|
||||
*/
|
||||
popMark() {
|
||||
const offset = this._marks.pop();
|
||||
if (offset === undefined) throw new Error('Mark stack empty');
|
||||
this.seek(offset);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer offset back to 0
|
||||
*/
|
||||
rewind() {
|
||||
this.offset = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the buffer has sufficient memory to write a given byteLength at the current pointer offset
|
||||
* If the buffer's memory is insufficient, this method will create a new buffer (a copy) with a length
|
||||
* that is twice (byteLength + current offset)
|
||||
*/
|
||||
ensureAvailable(byteLength: number) {
|
||||
if (byteLength === undefined) byteLength = 1;
|
||||
if (!this.available(byteLength)) {
|
||||
const lengthNeeded = this.offset + byteLength;
|
||||
const newLength = lengthNeeded * 2;
|
||||
const newArray = new Uint8Array(newLength);
|
||||
newArray.set(new Uint8Array(this.buffer));
|
||||
this.buffer = newArray.buffer;
|
||||
this.length = this.byteLength = newLength;
|
||||
this._data = new DataView(this.buffer);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte and return false if the byte's value is 0, or true otherwise
|
||||
* Moves pointer forward
|
||||
*/
|
||||
readBoolean() {
|
||||
return this.readUint8() !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a signed 8-bit integer and move pointer forward
|
||||
*/
|
||||
readInt8() {
|
||||
return this._data.getInt8(this.offset++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an unsigned 8-bit integer and move pointer forward
|
||||
*/
|
||||
readUint8() {
|
||||
return this._data.getUint8(this.offset++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link IOBuffer#readUint8}
|
||||
*/
|
||||
readByte() {
|
||||
return this.readUint8();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read n bytes and move pointer forward.
|
||||
*/
|
||||
readBytes(n: number) {
|
||||
if (n === undefined) n = 1;
|
||||
const bytes = new Uint8Array(n);
|
||||
for (let i = 0; i < n; i++) {
|
||||
bytes[i] = this.readByte();
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 16-bit signed integer and move pointer forward
|
||||
*/
|
||||
readInt16() {
|
||||
const value = this._data.getInt16(this.offset, this.littleEndian);
|
||||
this.offset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 16-bit unsigned integer and move pointer forward
|
||||
*/
|
||||
readUint16() {
|
||||
const value = this._data.getUint16(this.offset, this.littleEndian);
|
||||
this.offset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit signed integer and move pointer forward
|
||||
*/
|
||||
readInt32() {
|
||||
const value = this._data.getInt32(this.offset, this.littleEndian);
|
||||
this.offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit unsigned integer and move pointer forward
|
||||
*/
|
||||
readUint32() {
|
||||
const value = this._data.getUint32(this.offset, this.littleEndian);
|
||||
this.offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit floating number and move pointer forward
|
||||
*/
|
||||
readFloat32() {
|
||||
const value = this._data.getFloat32(this.offset, this.littleEndian);
|
||||
this.offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 64-bit floating number and move pointer forward
|
||||
*/
|
||||
readFloat64() {
|
||||
const value = this._data.getFloat64(this.offset, this.littleEndian);
|
||||
this.offset += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read 1-byte ascii character and move pointer forward
|
||||
*/
|
||||
readChar() {
|
||||
return String.fromCharCode(this.readInt8());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read n 1-byte ascii characters and move pointer forward
|
||||
*/
|
||||
readChars(n = 1) {
|
||||
charArray.length = n;
|
||||
for (let i = 0; i < n; i++) {
|
||||
charArray[i] = this.readChar();
|
||||
}
|
||||
return charArray.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 0xff if the passed value is truthy, 0x00 otherwise
|
||||
*/
|
||||
writeBoolean(value = false) {
|
||||
this.writeUint8(value ? 0xff : 0x00);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value as an 8-bit signed integer
|
||||
*/
|
||||
writeInt8(value: number) {
|
||||
this.ensureAvailable(1);
|
||||
this._data.setInt8(this.offset++, value);
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value as a 8-bit unsigned integer
|
||||
*/
|
||||
writeUint8(value: number) {
|
||||
this.ensureAvailable(1);
|
||||
this._data.setUint8(this.offset++, value);
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An alias for IOBuffer#writeUint8
|
||||
*/
|
||||
writeByte(value: number) {
|
||||
return this.writeUint8(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write bytes
|
||||
*/
|
||||
writeBytes(bytes: number[] | Uint8Array) {
|
||||
this.ensureAvailable(bytes.length);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
this._data.setUint8(this.offset++, bytes[i]);
|
||||
}
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value as an 16-bit signed integer
|
||||
*/
|
||||
writeInt16(value: number) {
|
||||
this.ensureAvailable(2);
|
||||
this._data.setInt16(this.offset, value, this.littleEndian);
|
||||
this.offset += 2;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value as a 16-bit unsigned integer
|
||||
*/
|
||||
writeUint16(value: number) {
|
||||
this.ensureAvailable(2);
|
||||
this._data.setUint16(this.offset, value, this.littleEndian);
|
||||
this.offset += 2;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 32-bit signed integer at the current pointer offset
|
||||
*/
|
||||
writeInt32(value: number) {
|
||||
this.ensureAvailable(4);
|
||||
this._data.setInt32(this.offset, value, this.littleEndian);
|
||||
this.offset += 4;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 32-bit unsigned integer at the current pointer offset
|
||||
*/
|
||||
writeUint32(value: number) {
|
||||
this.ensureAvailable(4);
|
||||
this._data.setUint32(this.offset, value, this.littleEndian);
|
||||
this.offset += 4;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 32-bit floating number at the current pointer offset
|
||||
*/
|
||||
writeFloat32(value: number) {
|
||||
this.ensureAvailable(4);
|
||||
this._data.setFloat32(this.offset, value, this.littleEndian);
|
||||
this.offset += 4;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 64-bit floating number at the current pointer offset
|
||||
*/
|
||||
writeFloat64(value: number) {
|
||||
this.ensureAvailable(8);
|
||||
this._data.setFloat64(this.offset, value, this.littleEndian);
|
||||
this.offset += 8;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the charCode of the passed string's first character to the current pointer offset
|
||||
*/
|
||||
writeChar(str: string) {
|
||||
return this.writeUint8(str.charCodeAt(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the charCodes of the passed string's characters to the current pointer offset
|
||||
*/
|
||||
writeChars(str: string) {
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
this.writeUint8(str.charCodeAt(i));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a Uint8Array view of the internal buffer.
|
||||
* The view starts at the byte offset and its length
|
||||
* is calculated to stop at the last written byte or the original length.
|
||||
*/
|
||||
toArray() {
|
||||
return new Uint8Array(this.buffer, this.byteOffset, this._lastWrittenByte);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the last written byte offset
|
||||
*/
|
||||
private _updateLastWrittenByte() {
|
||||
if (this.offset > this._lastWrittenByte) {
|
||||
this._lastWrittenByte = this.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
527
src/mol-io/common/netcdf/reader.ts
Normal file
527
src/mol-io/common/netcdf/reader.ts
Normal file
@@ -0,0 +1,527 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Adapted from https://github.com/cheminfo-js/netcdfjs
|
||||
* MIT License, Copyright (c) 2016 cheminfo
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
|
||||
import { IOBuffer } from '../io-buffer';
|
||||
|
||||
export interface NetCDFRecordDimension {
|
||||
length: number,
|
||||
id?: number,
|
||||
name?: string,
|
||||
recordStep?: number
|
||||
}
|
||||
|
||||
export interface NetCDFVariable {
|
||||
name: string
|
||||
dimensions: any[]
|
||||
attributes: any[]
|
||||
type: string
|
||||
size: number
|
||||
offset: number
|
||||
record: boolean
|
||||
}
|
||||
|
||||
export interface NetCDFHeader {
|
||||
recordDimension: NetCDFRecordDimension,
|
||||
version: number,
|
||||
dimensions: { name: string, size: number }[],
|
||||
globalAttributes: { name: string, type: string, value: string | number }[],
|
||||
variables: NetCDFVariable[]
|
||||
}
|
||||
|
||||
export interface NetCDFDimension {
|
||||
name: string,
|
||||
size: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a non-valid NetCDF exception if the statement it's true
|
||||
*/
|
||||
function notNetcdf(statement: boolean, reason: string) {
|
||||
if (statement) {
|
||||
throw new TypeError('Not a valid NetCDF v3.x file: ' + reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves 1, 2, or 3 bytes to next 4-byte boundary
|
||||
*/
|
||||
function padding(buffer: IOBuffer) {
|
||||
if ((buffer.offset % 4) !== 0) {
|
||||
buffer.skip(4 - (buffer.offset % 4));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the name
|
||||
*/
|
||||
function readName(buffer: IOBuffer) {
|
||||
// Read name
|
||||
const nameLength = buffer.readUint32();
|
||||
const name = buffer.readChars(nameLength);
|
||||
|
||||
// validate name
|
||||
// TODO
|
||||
|
||||
// Apply padding
|
||||
padding(buffer);
|
||||
return name;
|
||||
}
|
||||
|
||||
const types = {
|
||||
BYTE: 1,
|
||||
CHAR: 2,
|
||||
SHORT: 3,
|
||||
INT: 4,
|
||||
FLOAT: 5,
|
||||
DOUBLE: 6
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a number into their respective type
|
||||
*/
|
||||
function num2str(type: number) {
|
||||
switch (Number(type)) {
|
||||
case types.BYTE:
|
||||
return 'byte';
|
||||
case types.CHAR:
|
||||
return 'char';
|
||||
case types.SHORT:
|
||||
return 'short';
|
||||
case types.INT:
|
||||
return 'int';
|
||||
case types.FLOAT:
|
||||
return 'float';
|
||||
case types.DOUBLE:
|
||||
return 'double';
|
||||
default:
|
||||
return 'undefined';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a number type identifier to his size in bytes
|
||||
*/
|
||||
function num2bytes(type: number) {
|
||||
switch (Number(type)) {
|
||||
case types.BYTE:
|
||||
return 1;
|
||||
case types.CHAR:
|
||||
return 1;
|
||||
case types.SHORT:
|
||||
return 2;
|
||||
case types.INT:
|
||||
return 4;
|
||||
case types.FLOAT:
|
||||
return 4;
|
||||
case types.DOUBLE:
|
||||
return 8;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse search of num2str
|
||||
*/
|
||||
function str2num(type: string) {
|
||||
switch (String(type)) {
|
||||
case 'byte':
|
||||
return types.BYTE;
|
||||
case 'char':
|
||||
return types.CHAR;
|
||||
case 'short':
|
||||
return types.SHORT;
|
||||
case 'int':
|
||||
return types.INT;
|
||||
case 'float':
|
||||
return types.FLOAT;
|
||||
case 'double':
|
||||
return types.DOUBLE;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auxiliary function to read numeric data
|
||||
*/
|
||||
function readNumber(size: number, bufferReader: Function) {
|
||||
if (size !== 1) {
|
||||
const numbers = new Array(size);
|
||||
for (let i = 0; i < size; i++) {
|
||||
numbers[i] = bufferReader();
|
||||
}
|
||||
return numbers;
|
||||
} else {
|
||||
return bufferReader();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a type and a size reads the next element
|
||||
*/
|
||||
function readType(buffer: IOBuffer, type: number, size: number) {
|
||||
switch (type) {
|
||||
case types.BYTE:
|
||||
return buffer.readBytes(size);
|
||||
case types.CHAR:
|
||||
return trimNull(buffer.readChars(size));
|
||||
case types.SHORT:
|
||||
return readNumber(size, buffer.readInt16.bind(buffer));
|
||||
case types.INT:
|
||||
return readNumber(size, buffer.readInt32.bind(buffer));
|
||||
case types.FLOAT:
|
||||
return readNumber(size, buffer.readFloat32.bind(buffer));
|
||||
case types.DOUBLE:
|
||||
return readNumber(size, buffer.readFloat64.bind(buffer));
|
||||
default:
|
||||
notNetcdf(true, 'non valid type ' + type);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes null terminate value
|
||||
*/
|
||||
function trimNull(value: string) {
|
||||
if (value.charCodeAt(value.length - 1) === 0) {
|
||||
return value.substring(0, value.length - 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// const STREAMING = 4294967295;
|
||||
|
||||
/**
|
||||
* Read data for the given non-record variable
|
||||
*/
|
||||
function nonRecord(buffer: IOBuffer, variable: { type: string, size: number }) {
|
||||
// variable type
|
||||
const type = str2num(variable.type);
|
||||
|
||||
// size of the data
|
||||
const size = variable.size / num2bytes(type);
|
||||
|
||||
// iterates over the data
|
||||
const data = new Array(size);
|
||||
for (let i = 0; i < size; i++) {
|
||||
data[i] = readType(buffer, type, 1);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data for the given record variable
|
||||
*/
|
||||
function record(buffer: IOBuffer, variable: { type: string, size: number }, recordDimension: NetCDFRecordDimension) {
|
||||
// variable type
|
||||
const type = str2num(variable.type);
|
||||
const width = variable.size ? variable.size / num2bytes(type) : 1;
|
||||
|
||||
// size of the data
|
||||
// TODO streaming data
|
||||
const size = recordDimension.length;
|
||||
|
||||
// iterates over the data
|
||||
const data = new Array(size);
|
||||
const step = recordDimension.recordStep;
|
||||
|
||||
for (let i = 0; i < size; i++) {
|
||||
const currentOffset = buffer.offset;
|
||||
data[i] = readType(buffer, type, width);
|
||||
buffer.seek(currentOffset + step!);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Grammar constants
|
||||
const ZERO = 0;
|
||||
const NC_DIMENSION = 10;
|
||||
const NC_VARIABLE = 11;
|
||||
const NC_ATTRIBUTE = 12;
|
||||
|
||||
/**
|
||||
* Read the header of the file
|
||||
* Returns object with the fields:
|
||||
* - `recordDimension`: Number with the length of record dimension
|
||||
* - `dimensions`: List of dimensions
|
||||
* - `globalAttributes`: List of global attributes
|
||||
* - `variables`: List of variables
|
||||
*/
|
||||
function header(buffer: IOBuffer, version: number) {
|
||||
// Length of record dimension
|
||||
// sum of the varSize's of all the record variables.
|
||||
const header: Partial<NetCDFHeader> = { recordDimension: { length: buffer.readUint32() } };
|
||||
|
||||
// Version
|
||||
header.version = version;
|
||||
|
||||
// List of dimensions
|
||||
const dimList = dimensionsList(buffer) as { dimensions: NetCDFDimension[], recordId: number, recordName: string };
|
||||
header.recordDimension!.id = dimList.recordId;
|
||||
header.recordDimension!.name = dimList.recordName;
|
||||
header.dimensions = dimList.dimensions;
|
||||
|
||||
// List of global attributes
|
||||
header.globalAttributes = attributesList(buffer);
|
||||
|
||||
// List of variables
|
||||
const variables = variablesList(buffer, dimList.recordId, version) as { variables: any[], recordStep: number };
|
||||
header.variables = variables.variables;
|
||||
header.recordDimension!.recordStep = variables.recordStep;
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of dimensions
|
||||
*/
|
||||
function dimensionsList(buffer: IOBuffer) {
|
||||
let dimensions: NetCDFDimension[], recordId, recordName;
|
||||
const dimList = buffer.readUint32();
|
||||
if (dimList === ZERO) {
|
||||
notNetcdf((buffer.readUint32() !== ZERO), 'wrong empty tag for list of dimensions');
|
||||
return [];
|
||||
} else {
|
||||
notNetcdf((dimList !== NC_DIMENSION), 'wrong tag for list of dimensions');
|
||||
|
||||
// Length of dimensions
|
||||
const dimensionSize = buffer.readUint32();
|
||||
dimensions = new Array(dimensionSize);
|
||||
for (let dim = 0; dim < dimensionSize; dim++) {
|
||||
// Read name
|
||||
const name = readName(buffer);
|
||||
|
||||
// Read dimension size
|
||||
const size = buffer.readUint32();
|
||||
if (size === 0) {
|
||||
recordId = dim;
|
||||
recordName = name;
|
||||
}
|
||||
|
||||
dimensions[dim] = {
|
||||
name: name,
|
||||
size: size
|
||||
};
|
||||
}
|
||||
return {
|
||||
dimensions: dimensions,
|
||||
recordId: recordId,
|
||||
recordName: recordName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List of attributes
|
||||
*/
|
||||
function attributesList(buffer: IOBuffer) {
|
||||
let attributes: { name: string, type: ReturnType<typeof num2str>, value: any }[];
|
||||
const gAttList = buffer.readUint32();
|
||||
if (gAttList === ZERO) {
|
||||
notNetcdf((buffer.readUint32() !== ZERO), 'wrong empty tag for list of attributes');
|
||||
return [];
|
||||
} else {
|
||||
notNetcdf((gAttList !== NC_ATTRIBUTE), 'wrong tag for list of attributes');
|
||||
|
||||
// Length of attributes
|
||||
const attributeSize = buffer.readUint32();
|
||||
attributes = new Array(attributeSize);
|
||||
for (let gAtt = 0; gAtt < attributeSize; gAtt++) {
|
||||
// Read name
|
||||
const name = readName(buffer);
|
||||
|
||||
// Read type
|
||||
const type = buffer.readUint32();
|
||||
notNetcdf(((type < 1) || (type > 6)), 'non valid type ' + type);
|
||||
|
||||
// Read attribute
|
||||
const size = buffer.readUint32();
|
||||
const value = readType(buffer, type, size);
|
||||
|
||||
// Apply padding
|
||||
padding(buffer);
|
||||
|
||||
attributes[gAtt] = {
|
||||
name: name,
|
||||
type: num2str(type),
|
||||
value: value
|
||||
};
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of variables
|
||||
*/
|
||||
function variablesList(buffer: IOBuffer, recordId: number, version: number) {
|
||||
const varList = buffer.readUint32();
|
||||
let recordStep = 0;
|
||||
let variables;
|
||||
if (varList === ZERO) {
|
||||
notNetcdf(
|
||||
(buffer.readUint32() !== ZERO),
|
||||
'wrong empty tag for list of variables'
|
||||
);
|
||||
return [];
|
||||
} else {
|
||||
notNetcdf((varList !== NC_VARIABLE), 'wrong tag for list of variables');
|
||||
|
||||
// Length of variables
|
||||
const variableSize = buffer.readUint32();
|
||||
variables = new Array(variableSize);
|
||||
for (let v = 0; v < variableSize; v++) {
|
||||
// Read name
|
||||
const name = readName(buffer);
|
||||
|
||||
// Read dimensionality of the variable
|
||||
const dimensionality = buffer.readUint32();
|
||||
|
||||
// Index into the list of dimensions
|
||||
const dimensionsIds = new Array(dimensionality);
|
||||
for (let dim = 0; dim < dimensionality; dim++) {
|
||||
dimensionsIds[dim] = buffer.readUint32();
|
||||
}
|
||||
|
||||
// Read variables size
|
||||
const attributes = attributesList(buffer);
|
||||
|
||||
// Read type
|
||||
const type = buffer.readUint32();
|
||||
notNetcdf(((type < 1) && (type > 6)), 'non valid type ' + type);
|
||||
|
||||
// Read variable size
|
||||
// The 32-bit varSize field is not large enough to contain the
|
||||
// size of variables that require more than 2^32 - 4 bytes,
|
||||
// so 2^32 - 1 is used in the varSize field for such variables.
|
||||
const varSize = buffer.readUint32();
|
||||
|
||||
// Read offset
|
||||
let offset = buffer.readUint32();
|
||||
if (version === 2) {
|
||||
notNetcdf((offset > 0), 'offsets larger than 4GB not supported');
|
||||
offset = buffer.readUint32();
|
||||
}
|
||||
|
||||
// Count amount of record variables
|
||||
if (dimensionsIds[0] === recordId) {
|
||||
recordStep += varSize;
|
||||
}
|
||||
|
||||
variables[v] = {
|
||||
name: name,
|
||||
dimensions: dimensionsIds,
|
||||
attributes: attributes,
|
||||
type: num2str(type),
|
||||
size: varSize,
|
||||
offset: offset,
|
||||
record: (dimensionsIds[0] === recordId)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
variables: variables,
|
||||
recordStep: recordStep
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a NetCDF v3.x file
|
||||
* https://www.unidata.ucar.edu/software/netcdf/docs/file_format_specifications.html
|
||||
*/
|
||||
export class NetcdfReader {
|
||||
header: Partial<NetCDFHeader>;
|
||||
buffer: IOBuffer;
|
||||
|
||||
constructor(data: ArrayBuffer) {
|
||||
const buffer = new IOBuffer(data);
|
||||
buffer.setBigEndian();
|
||||
|
||||
// Validate that it's a NetCDF file
|
||||
notNetcdf((buffer.readChars(3) !== 'CDF'), 'should start with CDF');
|
||||
|
||||
// Check the NetCDF format
|
||||
const version = buffer.readByte();
|
||||
notNetcdf((version > 2), 'unknown version');
|
||||
|
||||
// Read the header
|
||||
this.header = header(buffer, version);
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version for the NetCDF format
|
||||
*/
|
||||
get version() {
|
||||
if (this.header.version === 1) {
|
||||
return 'classic format';
|
||||
} else {
|
||||
return '64-bit offset format';
|
||||
}
|
||||
}
|
||||
|
||||
get recordDimension() {
|
||||
return this.header.recordDimension;
|
||||
}
|
||||
|
||||
get dimensions() {
|
||||
return this.header.dimensions;
|
||||
}
|
||||
|
||||
get globalAttributes() {
|
||||
return this.header.globalAttributes;
|
||||
}
|
||||
|
||||
get variables() {
|
||||
return this.header.variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a variable is available
|
||||
* @param {string|object} variableName - Name of the variable to check
|
||||
* @return {Boolean} - Variable existence
|
||||
*/
|
||||
hasDataVariable(variableName: string) {
|
||||
return this.header.variables && this.header.variables.findIndex(val => val.name === variableName) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the data for a given variable
|
||||
* @param {string|object} variableName - Name of the variable to search or variable object
|
||||
* @return {Array} - List with the variable values
|
||||
*/
|
||||
getDataVariable(variableName: string | NetCDFVariable) {
|
||||
let variable: NetCDFVariable | undefined;
|
||||
if (typeof variableName === 'string') {
|
||||
// search the variable
|
||||
variable = this.header.variables?.find((val) => val.name === variableName);
|
||||
} else {
|
||||
variable = variableName;
|
||||
}
|
||||
|
||||
// throws if variable not found
|
||||
if (variable === undefined) throw new Error('variable not found');
|
||||
|
||||
// go to the offset position
|
||||
this.buffer.seek(variable.offset);
|
||||
|
||||
if (variable.record) {
|
||||
// record variable case
|
||||
return record(this.buffer, variable, this.header.recordDimension!);
|
||||
} else {
|
||||
// non-record variable case
|
||||
return nonRecord(this.buffer, variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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>
|
||||
@@ -45,7 +45,7 @@ type ColumnCtor = (field: Data.CifField, category: Data.CifCategory, key: string
|
||||
|
||||
function getColumnCtor(t: Column.Schema): ColumnCtor {
|
||||
switch (t.valueType) {
|
||||
case 'str': return (f, c, k) => createColumn(t, f, f.str, f.toStringArray);
|
||||
case 'str': return (f, c, k) => createStringColumn(t, f, f.str, f.toStringArray);
|
||||
case 'int': return (f, c, k) => createColumn(t, f, f.int, f.toIntArray);
|
||||
case 'float': return (f, c, k) => createColumn(t, f, f.float, f.toFloatArray);
|
||||
case 'list': throw new Error('Use createListColumn instead.');
|
||||
@@ -53,6 +53,27 @@ function getColumnCtor(t: Column.Schema): ColumnCtor {
|
||||
}
|
||||
}
|
||||
|
||||
function createStringColumn<T extends string>(schema: Column.Schema.Str | Column.Schema.Aliased<T>, field: Data.CifField, value: (row: number) => T, toArray: Column<T>['toArray']): Column<T> {
|
||||
return {
|
||||
schema,
|
||||
__array: field.__array,
|
||||
isDefined: field.isDefined,
|
||||
rowCount: field.rowCount,
|
||||
value: schema.transform === 'lowercase'
|
||||
? row => value(row).toLowerCase() as T
|
||||
: schema.transform === 'uppercase'
|
||||
? row => value(row).toUpperCase() as T
|
||||
: value,
|
||||
valueKind: field.valueKind,
|
||||
areValuesEqual: field.areValuesEqual,
|
||||
toArray: schema.transform === 'lowercase'
|
||||
? p => Array.from(toArray(p)).map(x => x.toLowerCase() as T)
|
||||
: schema.transform === 'uppercase'
|
||||
? p => Array.from(toArray(p)).map(x => x.toUpperCase() as T)
|
||||
: toArray,
|
||||
};
|
||||
}
|
||||
|
||||
function createColumn<T>(schema: Column.Schema, field: Data.CifField, value: (row: number) => T, toArray: Column<T>['toArray']): Column<T> {
|
||||
return {
|
||||
schema,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.356, IHM 1.17, MA 1.3.5.
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.357, IHM 1.17, MA 1.3.6.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
@@ -12,6 +12,7 @@ import Schema = Column.Schema;
|
||||
|
||||
const str = Schema.str;
|
||||
const float = Schema.float;
|
||||
const lstr = Schema.lstr;
|
||||
const Aliased = Schema.Aliased;
|
||||
const int = Schema.int;
|
||||
|
||||
@@ -58,7 +59,7 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* Defines the structural classification of the entity.
|
||||
*/
|
||||
type: Aliased<'Amino acid' | 'Aminoglycoside' | 'Anthracycline' | 'Anthraquinone' | 'Ansamycin' | 'Chalkophore' | 'Chromophore' | 'Glycopeptide' | 'Cyclic depsipeptide' | 'Cyclic lipopeptide' | 'Cyclic peptide' | 'Heterocyclic' | 'Imino sugar' | 'Keto acid' | 'Lipoglycopeptide' | 'Lipopeptide' | 'Macrolide' | 'Non-polymer' | 'Nucleoside' | 'Oligopeptide' | 'Oligosaccharide' | 'Peptaibol' | 'Peptide-like' | 'Polycyclic' | 'Polypeptide' | 'Polysaccharide' | 'Quinolone' | 'Thiolactone' | 'Thiopeptide' | 'Siderophore' | 'Unknown' | 'Chalkophore, Polypeptide'>(str),
|
||||
type: Aliased<'amino acid' | 'aminoglycoside' | 'anthracycline' | 'anthraquinone' | 'ansamycin' | 'chalkophore' | 'chromophore' | 'glycopeptide' | 'cyclic depsipeptide' | 'cyclic lipopeptide' | 'cyclic peptide' | 'heterocyclic' | 'imino sugar' | 'keto acid' | 'lipoglycopeptide' | 'lipopeptide' | 'macrolide' | 'non-polymer' | 'nucleoside' | 'oligopeptide' | 'oligosaccharide' | 'peptaibol' | 'peptide-like' | 'polycyclic' | 'polypeptide' | 'polysaccharide' | 'quinolone' | 'thiolactone' | 'thiopeptide' | 'siderophore' | 'unknown' | 'chalkophore, polypeptide'>(lstr),
|
||||
/**
|
||||
* Evidence for the assignment of _pdbx_reference_molecule.type
|
||||
*/
|
||||
@@ -66,7 +67,7 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* Broadly defines the function of the entity.
|
||||
*/
|
||||
class: Aliased<'Antagonist' | 'Antibiotic' | 'Anticancer' | 'Anticoagulant' | 'Antifungal' | 'Antigen' | 'Antiinflammatory' | 'Antimicrobial' | 'Antineoplastic' | 'Antiparasitic' | 'Antiretroviral' | 'Anthelmintic' | 'Antithrombotic' | 'Antitumor' | 'Antiviral' | 'CASPASE inhibitor' | 'Chaperone binding' | 'Enzyme inhibitor' | 'Drug delivery' | 'Glycan component' | 'Growth factor' | 'Immunosuppressant' | 'Inducer' | 'Inhibitor' | 'Lantibiotic' | 'Metabolism' | 'Metal transport' | 'Nutrient' | 'Oxidation-reduction' | 'Protein binding' | 'Receptor' | 'Substrate analog' | 'Synthetic opioid' | 'Thrombin inhibitor' | 'Transition state mimetic' | 'Transport activator' | 'Trypsin inhibitor' | 'Toxin' | 'Unknown' | 'Water retention' | 'Anticoagulant, Antithrombotic' | 'Antibiotic, Antimicrobial' | 'Antibiotic, Anthelmintic' | 'Antibiotic, Antineoplastic' | 'Antimicrobial, Antiretroviral' | 'Antimicrobial, Antitumor' | 'Antimicrobial, Antiparasitic, Antibiotic' | 'Thrombin inhibitor, Trypsin inhibitor'>(str),
|
||||
class: Aliased<'antagonist' | 'antibiotic' | 'anticancer' | 'anticoagulant' | 'antifungal' | 'antigen' | 'antiinflammatory' | 'antimicrobial' | 'antineoplastic' | 'antiparasitic' | 'antiretroviral' | 'anthelmintic' | 'antithrombotic' | 'antitumor' | 'antiviral' | 'caspase inhibitor' | 'chaperone binding' | 'enzyme inhibitor' | 'drug delivery' | 'glycan component' | 'growth factor' | 'immunosuppressant' | 'inducer' | 'inhibitor' | 'lantibiotic' | 'metabolism' | 'metal transport' | 'nutrient' | 'oxidation-reduction' | 'protein binding' | 'receptor' | 'substrate analog' | 'synthetic opioid' | 'thrombin inhibitor' | 'transition state mimetic' | 'transport activator' | 'trypsin inhibitor' | 'toxin' | 'unknown' | 'water retention' | 'anticoagulant, antithrombotic' | 'antibiotic, antimicrobial' | 'antibiotic, anthelmintic' | 'antibiotic, antineoplastic' | 'antimicrobial, antiretroviral' | 'antimicrobial, antitumor' | 'antimicrobial, antiparasitic, antibiotic' | 'thrombin inhibitor, trypsin inhibitor'>(lstr),
|
||||
/**
|
||||
* Evidence for the assignment of _pdbx_reference_molecule.class
|
||||
*/
|
||||
@@ -78,7 +79,7 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* Defines how this entity is represented in PDB data files.
|
||||
*/
|
||||
represent_as: Aliased<'polymer' | 'single molecule' | 'branched'>(str),
|
||||
represent_as: Aliased<'polymer' | 'single molecule' | 'branched'>(lstr),
|
||||
/**
|
||||
* For entities represented as single molecules, the identifier
|
||||
* corresponding to the chemical definition for the molecule.
|
||||
@@ -99,7 +100,7 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* Defines the current PDB release status for this molecule definition.
|
||||
*/
|
||||
release_status: Aliased<'REL' | 'HOLD' | 'OBS' | 'WAIT'>(str),
|
||||
release_status: Aliased<'rel' | 'hold' | 'obs' | 'wait'>(lstr),
|
||||
/**
|
||||
* Assigns the identifier for the reference molecule which have been replaced
|
||||
* by this reference molecule.
|
||||
@@ -129,7 +130,7 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* Defines the polymer characteristic of the entity.
|
||||
*/
|
||||
type: Aliased<'polymer' | 'polymer-like' | 'non-polymer' | 'branched'>(str),
|
||||
type: Aliased<'polymer' | 'polymer-like' | 'non-polymer' | 'branched'>(lstr),
|
||||
/**
|
||||
* Additional details about this entity.
|
||||
*/
|
||||
@@ -249,7 +250,7 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* The bond order target for the chemical linkage.
|
||||
*/
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str),
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(lstr),
|
||||
/**
|
||||
* The entity component identifier for the first of two entities containing the linkage.
|
||||
*/
|
||||
@@ -335,7 +336,7 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* The bond order target for the non-standard linkage.
|
||||
*/
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str),
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Data items in the PDBX_REFERENCE_ENTITY_POLY category record details about
|
||||
@@ -400,11 +401,11 @@ export const BIRD_Schema = {
|
||||
/**
|
||||
* A flag to indicate that this monomer is observed in the instance example.
|
||||
*/
|
||||
observed: Aliased<'Y' | 'N'>(str),
|
||||
observed: Aliased<'y' | 'n'>(lstr),
|
||||
/**
|
||||
* A flag to indicate that sequence heterogeneity at this monomer position.
|
||||
*/
|
||||
hetero: Aliased<'Y' | 'N'>(str),
|
||||
hetero: Aliased<'y' | 'n'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Additional features associated with the reference entity.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.356, IHM 1.17, MA 1.3.5.
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.357, IHM 1.17, MA 1.3.6.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
@@ -13,6 +13,7 @@ import Schema = Column.Schema;
|
||||
const str = Schema.str;
|
||||
const float = Schema.float;
|
||||
const List = Schema.List;
|
||||
const lstr = Schema.lstr;
|
||||
const Aliased = Schema.Aliased;
|
||||
const int = Schema.int;
|
||||
const coord = Schema.coord;
|
||||
@@ -103,7 +104,7 @@ export const CCD_Schema = {
|
||||
* linking monomers, monomers with some type of N-terminal (or 5')
|
||||
* cap and monomers with some type of C-terminal (or 3') cap.
|
||||
*/
|
||||
type: Aliased<'D-peptide linking' | 'L-peptide linking' | 'D-peptide NH3 amino terminus' | 'L-peptide NH3 amino terminus' | 'D-peptide COOH carboxy terminus' | 'L-peptide COOH carboxy terminus' | 'DNA linking' | 'RNA linking' | 'L-RNA linking' | 'L-DNA linking' | 'DNA OH 5 prime terminus' | 'RNA OH 5 prime terminus' | 'DNA OH 3 prime terminus' | 'RNA OH 3 prime terminus' | 'D-saccharide, beta linking' | 'D-saccharide, alpha linking' | 'L-saccharide, beta linking' | 'L-saccharide, alpha linking' | 'L-saccharide' | 'D-saccharide' | 'saccharide' | 'non-polymer' | 'peptide linking' | 'peptide-like' | 'L-gamma-peptide, C-delta linking' | 'D-gamma-peptide, C-delta linking' | 'L-beta-peptide, C-gamma linking' | 'D-beta-peptide, C-gamma linking' | 'other'>(str),
|
||||
type: Aliased<'d-peptide linking' | 'l-peptide linking' | 'd-peptide nh3 amino terminus' | 'l-peptide nh3 amino terminus' | 'd-peptide cooh carboxy terminus' | 'l-peptide cooh carboxy terminus' | 'dna linking' | 'rna linking' | 'l-rna linking' | 'l-dna linking' | 'dna oh 5 prime terminus' | 'rna oh 5 prime terminus' | 'dna oh 3 prime terminus' | 'rna oh 3 prime terminus' | 'd-saccharide, beta linking' | 'd-saccharide, alpha linking' | 'l-saccharide, beta linking' | 'l-saccharide, alpha linking' | 'l-saccharide' | 'd-saccharide' | 'saccharide' | 'non-polymer' | 'peptide linking' | 'peptide-like' | 'l-gamma-peptide, c-delta linking' | 'd-gamma-peptide, c-delta linking' | 'l-beta-peptide, c-gamma linking' | 'd-beta-peptide, c-gamma linking' | 'other'>(lstr),
|
||||
/**
|
||||
* Synonym list for the component.
|
||||
*/
|
||||
@@ -154,11 +155,11 @@ export const CCD_Schema = {
|
||||
/**
|
||||
* This data item identifies if ideal coordinates are missing in this definition.
|
||||
*/
|
||||
pdbx_ideal_coordinates_missing_flag: Aliased<'Y' | 'N'>(str),
|
||||
pdbx_ideal_coordinates_missing_flag: Aliased<'y' | 'n'>(lstr),
|
||||
/**
|
||||
* This data item identifies if model coordinates are missing in this definition.
|
||||
*/
|
||||
pdbx_model_coordinates_missing_flag: Aliased<'Y' | 'N'>(str),
|
||||
pdbx_model_coordinates_missing_flag: Aliased<'y' | 'n'>(lstr),
|
||||
/**
|
||||
* Date component was added to database.
|
||||
*/
|
||||
@@ -279,15 +280,15 @@ export const CCD_Schema = {
|
||||
/**
|
||||
* The chiral configuration of the atom that is a chiral center.
|
||||
*/
|
||||
pdbx_stereo_config: Aliased<'R' | 'S' | 'N'>(str),
|
||||
pdbx_stereo_config: Aliased<'r' | 's' | 'n'>(lstr),
|
||||
/**
|
||||
* A flag indicating an aromatic atom.
|
||||
*/
|
||||
pdbx_aromatic_flag: Aliased<'Y' | 'N'>(str),
|
||||
pdbx_aromatic_flag: Aliased<'y' | 'n'>(lstr),
|
||||
/**
|
||||
* A flag indicating a leaving atom.
|
||||
*/
|
||||
pdbx_leaving_atom_flag: Aliased<'Y' | 'N'>(str),
|
||||
pdbx_leaving_atom_flag: Aliased<'y' | 'n'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Data items in the CHEM_COMP_BOND category record details about
|
||||
@@ -320,7 +321,7 @@ export const CCD_Schema = {
|
||||
* bond associated with the specified atoms, expressed as a bond
|
||||
* order.
|
||||
*/
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str),
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(lstr),
|
||||
/**
|
||||
* Ordinal index for the component bond list.
|
||||
*/
|
||||
@@ -328,11 +329,11 @@ export const CCD_Schema = {
|
||||
/**
|
||||
* Stereochemical configuration across a double bond.
|
||||
*/
|
||||
pdbx_stereo_config: Aliased<'E' | 'Z' | 'N'>(str),
|
||||
pdbx_stereo_config: Aliased<'e' | 'z' | 'n'>(lstr),
|
||||
/**
|
||||
* A flag indicating an aromatic bond.
|
||||
*/
|
||||
pdbx_aromatic_flag: Aliased<'Y' | 'N'>(str),
|
||||
pdbx_aromatic_flag: Aliased<'y' | 'n'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Data items in the CHEM_COMP_DESCRIPTOR category provide
|
||||
@@ -352,7 +353,7 @@ export const CCD_Schema = {
|
||||
/**
|
||||
* This data item contains the descriptor type.
|
||||
*/
|
||||
type: Aliased<'SMILES_CANNONICAL' | 'SMILES_CANONICAL' | 'SMILES' | 'InChI' | 'InChI_MAIN' | 'InChI_MAIN_FORMULA' | 'InChI_MAIN_CONNECT' | 'InChI_MAIN_HATOM' | 'InChI_CHARGE' | 'InChI_STEREO' | 'InChI_ISOTOPE' | 'InChI_FIXEDH' | 'InChI_RECONNECT' | 'InChIKey'>(str),
|
||||
type: Aliased<'smiles_cannonical' | 'smiles_canonical' | 'smiles' | 'inchi' | 'inchi_main' | 'inchi_main_formula' | 'inchi_main_connect' | 'inchi_main_hatom' | 'inchi_charge' | 'inchi_stereo' | 'inchi_isotope' | 'inchi_fixedh' | 'inchi_reconnect' | 'inchikey'>(lstr),
|
||||
/**
|
||||
* This data item contains the name of the program
|
||||
* or library used to compute the descriptor.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -25,9 +25,9 @@ export const mmCIF_chemCompBond_schema = {
|
||||
molstar_protonation_variant: Column.Schema.Str()
|
||||
};
|
||||
|
||||
/** Has `type` extended with 'Ion' and 'Lipid' */
|
||||
/** Has `type` extended with 'ION' and 'LIPID' */
|
||||
export const mmCIF_chemComp_schema = {
|
||||
...mmCIF_Schema.chem_comp,
|
||||
type: Column.Schema.Aliased<mmCIF_Schema['chem_comp']['type']['T'] | 'Ion' | 'Lipid'>(Column.Schema.str)
|
||||
type: Column.Schema.Aliased<mmCIF_Schema['chem_comp']['type']['T'] | 'ion' | 'lipid'>(Column.Schema.str)
|
||||
};
|
||||
export type mmCIF_chemComp_schema = typeof mmCIF_chemComp_schema;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.356, IHM 1.17, MA 1.3.5.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.357, IHM 1.17, MA 1.3.6.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
@@ -17,6 +17,7 @@ const coord = Schema.coord;
|
||||
const Aliased = Schema.Aliased;
|
||||
const Matrix = Schema.Matrix;
|
||||
const Vector = Schema.Vector;
|
||||
const lstr = Schema.lstr;
|
||||
const List = Schema.List;
|
||||
|
||||
export const mmCIF_Schema = {
|
||||
@@ -512,7 +513,7 @@ export const mmCIF_Schema = {
|
||||
* _chem_comp.mon_nstd_parent, _chem_comp.mon_nstd_class and
|
||||
* _chem_comp.mon_nstd_details data items.
|
||||
*/
|
||||
mon_nstd_flag: Aliased<'no' | 'n' | 'yes' | 'y'>(str),
|
||||
mon_nstd_flag: Aliased<'no' | 'n' | 'yes' | 'y'>(lstr),
|
||||
/**
|
||||
* The full name of the component.
|
||||
*/
|
||||
@@ -523,7 +524,7 @@ export const mmCIF_Schema = {
|
||||
* linking monomers, monomers with some type of N-terminal (or 5')
|
||||
* cap and monomers with some type of C-terminal (or 3') cap.
|
||||
*/
|
||||
type: Aliased<'D-peptide linking' | 'L-peptide linking' | 'D-peptide NH3 amino terminus' | 'L-peptide NH3 amino terminus' | 'D-peptide COOH carboxy terminus' | 'L-peptide COOH carboxy terminus' | 'DNA linking' | 'RNA linking' | 'L-RNA linking' | 'L-DNA linking' | 'DNA OH 5 prime terminus' | 'RNA OH 5 prime terminus' | 'DNA OH 3 prime terminus' | 'RNA OH 3 prime terminus' | 'D-saccharide, beta linking' | 'D-saccharide, alpha linking' | 'L-saccharide, beta linking' | 'L-saccharide, alpha linking' | 'L-saccharide' | 'D-saccharide' | 'saccharide' | 'non-polymer' | 'peptide linking' | 'peptide-like' | 'L-gamma-peptide, C-delta linking' | 'D-gamma-peptide, C-delta linking' | 'L-beta-peptide, C-gamma linking' | 'D-beta-peptide, C-gamma linking' | 'other'>(str),
|
||||
type: Aliased<'d-peptide linking' | 'l-peptide linking' | 'd-peptide nh3 amino terminus' | 'l-peptide nh3 amino terminus' | 'd-peptide cooh carboxy terminus' | 'l-peptide cooh carboxy terminus' | 'dna linking' | 'rna linking' | 'l-rna linking' | 'l-dna linking' | 'dna oh 5 prime terminus' | 'rna oh 5 prime terminus' | 'dna oh 3 prime terminus' | 'rna oh 3 prime terminus' | 'd-saccharide, beta linking' | 'd-saccharide, alpha linking' | 'l-saccharide, beta linking' | 'l-saccharide, alpha linking' | 'l-saccharide' | 'd-saccharide' | 'saccharide' | 'non-polymer' | 'peptide linking' | 'peptide-like' | 'l-gamma-peptide, c-delta linking' | 'd-gamma-peptide, c-delta linking' | 'l-beta-peptide, c-gamma linking' | 'd-beta-peptide, c-gamma linking' | 'other'>(lstr),
|
||||
/**
|
||||
* Synonym list for the component.
|
||||
*/
|
||||
@@ -560,7 +561,7 @@ export const mmCIF_Schema = {
|
||||
* bond associated with the specified atoms, expressed as a bond
|
||||
* order.
|
||||
*/
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str),
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(lstr),
|
||||
/**
|
||||
* Ordinal index for the component bond list.
|
||||
*/
|
||||
@@ -568,11 +569,11 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* Stereochemical configuration across a double bond.
|
||||
*/
|
||||
pdbx_stereo_config: Aliased<'E' | 'Z' | 'N'>(str),
|
||||
pdbx_stereo_config: Aliased<'e' | 'z' | 'n'>(lstr),
|
||||
/**
|
||||
* A flag indicating an aromatic bond.
|
||||
*/
|
||||
pdbx_aromatic_flag: Aliased<'Y' | 'N'>(str),
|
||||
pdbx_aromatic_flag: Aliased<'y' | 'n'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Data items in the CITATION category record details about the
|
||||
@@ -704,7 +705,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* An abbreviation that identifies the database.
|
||||
*/
|
||||
database_id: Aliased<'AlphaFoldDB' | 'CAS' | 'CSD' | 'EMDB' | 'ICSD' | 'ModelArchive' | 'MDF' | 'MODBASE' | 'NDB' | 'NBS' | 'PDB' | 'PDF' | 'RCSB' | 'SWISS-MODEL_REPOSITORY' | 'EBI' | 'PDBE' | 'BMRB' | 'WWPDB' | 'PDB_ACC'>(str),
|
||||
database_id: Aliased<'alphafolddb' | 'cas' | 'csd' | 'emdb' | 'icsd' | 'modelarchive' | 'mdf' | 'modbase' | 'ndb' | 'nbs' | 'pdb' | 'pdf' | 'rcsb' | 'swiss-model_repository' | 'ebi' | 'pdbe' | 'bmrb' | 'wwpdb' | 'pdb_acc'>(lstr),
|
||||
/**
|
||||
* The code assigned by the database identified in
|
||||
* _database_2.database_id.
|
||||
@@ -767,7 +768,7 @@ export const mmCIF_Schema = {
|
||||
* manipulated sources are expected to have further information in
|
||||
* the ENTITY_SRC_GEN category.
|
||||
*/
|
||||
src_method: Aliased<'nat' | 'man' | 'syn'>(str),
|
||||
src_method: Aliased<'nat' | 'man' | 'syn'>(lstr),
|
||||
/**
|
||||
* Defines the type of the entity.
|
||||
*
|
||||
@@ -780,7 +781,7 @@ export const mmCIF_Schema = {
|
||||
* Water entities are not expected to have corresponding
|
||||
* entries in the ENTITY category.
|
||||
*/
|
||||
type: Aliased<'polymer' | 'non-polymer' | 'macrolide' | 'water' | 'branched'>(str),
|
||||
type: Aliased<'polymer' | 'non-polymer' | 'macrolide' | 'water' | 'branched'>(lstr),
|
||||
/**
|
||||
* A description of the entity.
|
||||
*
|
||||
@@ -820,12 +821,12 @@ export const mmCIF_Schema = {
|
||||
* one monomer-to-monomer link different from that implied by
|
||||
* _entity_poly.type.
|
||||
*/
|
||||
nstd_linkage: Aliased<'no' | 'n' | 'yes' | 'y'>(str),
|
||||
nstd_linkage: Aliased<'no' | 'n' | 'yes' | 'y'>(lstr),
|
||||
/**
|
||||
* A flag to indicate whether the polymer contains at least
|
||||
* one monomer that is not considered standard.
|
||||
*/
|
||||
nstd_monomer: Aliased<'no' | 'n' | 'yes' | 'y'>(str),
|
||||
nstd_monomer: Aliased<'no' | 'n' | 'yes' | 'y'>(lstr),
|
||||
/**
|
||||
* The type of the polymer.
|
||||
*/
|
||||
@@ -894,6 +895,10 @@ export const mmCIF_Schema = {
|
||||
* parent is not specified. Deoxynucleotides are
|
||||
* represented by their canonical one-letter codes of A,
|
||||
* C, G, or T.
|
||||
*
|
||||
* For modifications with several parent amino acids,
|
||||
* all corresponding parent amino acid codes will be listed
|
||||
* (ex. chromophores).
|
||||
*/
|
||||
pdbx_seq_one_letter_code_can: str,
|
||||
/**
|
||||
@@ -919,7 +924,7 @@ export const mmCIF_Schema = {
|
||||
* A flag to indicate whether this monomer in the polymer is
|
||||
* heterogeneous in sequence.
|
||||
*/
|
||||
hetero: Aliased<'no' | 'n' | 'yes' | 'y'>(str),
|
||||
hetero: Aliased<'no' | 'n' | 'yes' | 'y'>(lstr),
|
||||
/**
|
||||
* This data item is a pointer to _chem_comp.id in the CHEM_COMP
|
||||
* category.
|
||||
@@ -996,7 +1001,7 @@ export const mmCIF_Schema = {
|
||||
* The classification of the software according to the most
|
||||
* common types.
|
||||
*/
|
||||
type: Aliased<'program' | 'library' | 'package' | 'filter' | 'jiffy' | 'other'>(str),
|
||||
type: Aliased<'program' | 'library' | 'package' | 'filter' | 'jiffy' | 'other'>(lstr),
|
||||
/**
|
||||
* The version of the software.
|
||||
*/
|
||||
@@ -1119,7 +1124,7 @@ export const mmCIF_Schema = {
|
||||
* This data item is a pointer to _struct_conf_type.id in the
|
||||
* STRUCT_CONF_TYPE category.
|
||||
*/
|
||||
conf_type_id: Aliased<'BEND' | 'HELX_P' | 'HELX_OT_P' | 'HELX_RH_P' | 'HELX_RH_OT_P' | 'HELX_RH_AL_P' | 'HELX_RH_GA_P' | 'HELX_RH_OM_P' | 'HELX_RH_PI_P' | 'HELX_RH_27_P' | 'HELX_RH_3T_P' | 'HELX_RH_PP_P' | 'HELX_LH_P' | 'HELX_LH_OT_P' | 'HELX_LH_AL_P' | 'HELX_LH_GA_P' | 'HELX_LH_OM_P' | 'HELX_LH_PI_P' | 'HELX_LH_27_P' | 'HELX_LH_3T_P' | 'HELX_LH_PP_P' | 'HELX_N' | 'HELX_OT_N' | 'HELX_RH_N' | 'HELX_RH_OT_N' | 'HELX_RH_A_N' | 'HELX_RH_B_N' | 'HELX_RH_Z_N' | 'HELX_LH_N' | 'HELX_LH_OT_N' | 'HELX_LH_A_N' | 'HELX_LH_B_N' | 'HELX_LH_Z_N' | 'TURN_P' | 'TURN_OT_P' | 'TURN_TY1_P' | 'TURN_TY1P_P' | 'TURN_TY2_P' | 'TURN_TY2P_P' | 'TURN_TY3_P' | 'TURN_TY3P_P' | 'STRN' | 'OTHER'>(str),
|
||||
conf_type_id: Aliased<'bend' | 'helx_p' | 'helx_ot_p' | 'helx_rh_p' | 'helx_rh_ot_p' | 'helx_rh_al_p' | 'helx_rh_ga_p' | 'helx_rh_om_p' | 'helx_rh_pi_p' | 'helx_rh_27_p' | 'helx_rh_3t_p' | 'helx_rh_pp_p' | 'helx_lh_p' | 'helx_lh_ot_p' | 'helx_lh_al_p' | 'helx_lh_ga_p' | 'helx_lh_om_p' | 'helx_lh_pi_p' | 'helx_lh_27_p' | 'helx_lh_3t_p' | 'helx_lh_pp_p' | 'helx_n' | 'helx_ot_n' | 'helx_rh_n' | 'helx_rh_ot_n' | 'helx_rh_a_n' | 'helx_rh_b_n' | 'helx_rh_z_n' | 'helx_lh_n' | 'helx_lh_ot_n' | 'helx_lh_a_n' | 'helx_lh_b_n' | 'helx_lh_z_n' | 'turn_p' | 'turn_ot_p' | 'turn_ty1_p' | 'turn_ty1p_p' | 'turn_ty2_p' | 'turn_ty2p_p' | 'turn_ty3_p' | 'turn_ty3p_p' | 'strn' | 'other'>(lstr),
|
||||
/**
|
||||
* A description of special aspects of the conformation assignment.
|
||||
*/
|
||||
@@ -1219,7 +1224,7 @@ export const mmCIF_Schema = {
|
||||
* This data item is a pointer to _struct_conn_type.id in the
|
||||
* STRUCT_CONN_TYPE category.
|
||||
*/
|
||||
conn_type_id: Aliased<'covale' | 'disulf' | 'metalc' | 'hydrog'>(str),
|
||||
conn_type_id: Aliased<'covale' | 'disulf' | 'metalc' | 'hydrog'>(lstr),
|
||||
/**
|
||||
* A description of special aspects of the connection.
|
||||
*/
|
||||
@@ -1439,7 +1444,7 @@ export const mmCIF_Schema = {
|
||||
* The chemical bond order associated with the specified atoms in
|
||||
* this contact.
|
||||
*/
|
||||
pdbx_value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad'>(str),
|
||||
pdbx_value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Data items in the STRUCT_CONN_TYPE category record details
|
||||
@@ -1454,7 +1459,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The chemical or structural type of the interaction.
|
||||
*/
|
||||
id: Aliased<'covale' | 'disulf' | 'hydrog' | 'metalc' | 'mismat' | 'saltbr' | 'modres' | 'covale_base' | 'covale_sugar' | 'covale_phosphate'>(str),
|
||||
id: Aliased<'covale' | 'disulf' | 'hydrog' | 'metalc' | 'mismat' | 'saltbr' | 'modres' | 'covale_base' | 'covale_sugar' | 'covale_phosphate'>(lstr),
|
||||
/**
|
||||
* A reference that specifies the criteria used to define the
|
||||
* interaction.
|
||||
@@ -1808,7 +1813,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The cell settings for this space-group symmetry.
|
||||
*/
|
||||
cell_setting: Aliased<'triclinic' | 'monoclinic' | 'orthorhombic' | 'tetragonal' | 'rhombohedral' | 'trigonal' | 'hexagonal' | 'cubic'>(str),
|
||||
cell_setting: Aliased<'triclinic' | 'monoclinic' | 'orthorhombic' | 'tetragonal' | 'rhombohedral' | 'trigonal' | 'hexagonal' | 'cubic'>(lstr),
|
||||
/**
|
||||
* Space-group number from International Tables for Crystallography
|
||||
* Vol. A (2002).
|
||||
@@ -1868,7 +1873,7 @@ export const mmCIF_Schema = {
|
||||
* This code indicates whether the entry belongs to
|
||||
* Structural Genomics Project.
|
||||
*/
|
||||
SG_entry: Aliased<'Y' | 'N'>(str),
|
||||
SG_entry: Aliased<'y' | 'n'>(lstr),
|
||||
/**
|
||||
* The site where the file was deposited.
|
||||
*/
|
||||
@@ -1892,7 +1897,7 @@ export const mmCIF_Schema = {
|
||||
* A value of 'N' indicates that the no PDB format data file is
|
||||
* corresponding to this entry is available in the PDB archive.
|
||||
*/
|
||||
pdb_format_compatible: Aliased<'Y' | 'N'>(str),
|
||||
pdb_format_compatible: Aliased<'y' | 'n'>(lstr),
|
||||
},
|
||||
/**
|
||||
* The PDBX_NONPOLY_SCHEME category provides residue level nomenclature
|
||||
@@ -2045,7 +2050,7 @@ export const mmCIF_Schema = {
|
||||
* The value of polymer flag indicates whether the unobserved or
|
||||
* zero occupancy residue is part of a polymer chain or not
|
||||
*/
|
||||
polymer_flag: Aliased<'Y' | 'N'>(str),
|
||||
polymer_flag: Aliased<'y' | 'n'>(lstr),
|
||||
/**
|
||||
* The value of occupancy flag indicates whether the residue
|
||||
* is unobserved (= 1) or the coordinates have an occupancy of zero (=0)
|
||||
@@ -2298,7 +2303,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* Defines the polymer characteristic of the entity.
|
||||
*/
|
||||
type: Aliased<'polymer' | 'polymer-like' | 'non-polymer' | 'branched'>(str),
|
||||
type: Aliased<'polymer' | 'polymer-like' | 'non-polymer' | 'branched'>(lstr),
|
||||
/**
|
||||
* Additional details about this entity.
|
||||
*/
|
||||
@@ -2393,7 +2398,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The bond order target for the chemical linkage.
|
||||
*/
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str),
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(lstr),
|
||||
/**
|
||||
* The entity component identifier for the first of two entities containing the linkage.
|
||||
*/
|
||||
@@ -2479,7 +2484,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The bond order target for the non-standard linkage.
|
||||
*/
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str),
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Data items in the PDBX_MOLECULE category identify reference molecules
|
||||
@@ -2514,11 +2519,11 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* Broadly defines the function of the molecule.
|
||||
*/
|
||||
class: Aliased<'Antagonist' | 'Antibiotic' | 'Anticancer' | 'Anticoagulant' | 'Antifungal' | 'Antigen' | 'Antiinflammatory' | 'Antimicrobial' | 'Antineoplastic' | 'Antiparasitic' | 'Antiretroviral' | 'Anthelmintic' | 'Antithrombotic' | 'Antitumor' | 'Antiviral' | 'CASPASE inhibitor' | 'Chaperone binding' | 'Enzyme inhibitor' | 'Drug delivery' | 'Glycan component' | 'Growth factor' | 'Immunosuppressant' | 'Inducer' | 'Inhibitor' | 'Lantibiotic' | 'Metabolism' | 'Metal transport' | 'Nutrient' | 'Oxidation-reduction' | 'Protein binding' | 'Receptor' | 'Substrate analog' | 'Synthetic opioid' | 'Thrombin inhibitor' | 'Transition state mimetic' | 'Transport activator' | 'Trypsin inhibitor' | 'Toxin' | 'Unknown' | 'Water retention' | 'Anticoagulant, Antithrombotic' | 'Antibiotic, Antimicrobial' | 'Antibiotic, Anthelmintic' | 'Antibiotic, Antineoplastic' | 'Antimicrobial, Antiretroviral' | 'Antimicrobial, Antitumor' | 'Antimicrobial, Antiparasitic, Antibiotic' | 'Thrombin inhibitor, Trypsin inhibitor'>(str),
|
||||
class: Aliased<'antagonist' | 'antibiotic' | 'anticancer' | 'anticoagulant' | 'antifungal' | 'antigen' | 'antiinflammatory' | 'antimicrobial' | 'antineoplastic' | 'antiparasitic' | 'antiretroviral' | 'anthelmintic' | 'antithrombotic' | 'antitumor' | 'antiviral' | 'caspase inhibitor' | 'chaperone binding' | 'enzyme inhibitor' | 'drug delivery' | 'glycan component' | 'growth factor' | 'immunosuppressant' | 'inducer' | 'inhibitor' | 'lantibiotic' | 'metabolism' | 'metal transport' | 'nutrient' | 'oxidation-reduction' | 'protein binding' | 'receptor' | 'substrate analog' | 'synthetic opioid' | 'thrombin inhibitor' | 'transition state mimetic' | 'transport activator' | 'trypsin inhibitor' | 'toxin' | 'unknown' | 'water retention' | 'anticoagulant, antithrombotic' | 'antibiotic, antimicrobial' | 'antibiotic, anthelmintic' | 'antibiotic, antineoplastic' | 'antimicrobial, antiretroviral' | 'antimicrobial, antitumor' | 'antimicrobial, antiparasitic, antibiotic' | 'thrombin inhibitor, trypsin inhibitor'>(lstr),
|
||||
/**
|
||||
* Defines the structural classification of the molecule.
|
||||
*/
|
||||
type: Aliased<'Amino acid' | 'Aminoglycoside' | 'Anthracycline' | 'Anthraquinone' | 'Ansamycin' | 'Chalkophore' | 'Chromophore' | 'Glycopeptide' | 'Cyclic depsipeptide' | 'Cyclic lipopeptide' | 'Cyclic peptide' | 'Heterocyclic' | 'Imino sugar' | 'Keto acid' | 'Lipoglycopeptide' | 'Lipopeptide' | 'Macrolide' | 'Non-polymer' | 'Nucleoside' | 'Oligopeptide' | 'Oligosaccharide' | 'Peptaibol' | 'Peptide-like' | 'Polycyclic' | 'Polypeptide' | 'Polysaccharide' | 'Quinolone' | 'Thiolactone' | 'Thiopeptide' | 'Siderophore' | 'Unknown' | 'Chalkophore, Polypeptide'>(str),
|
||||
type: Aliased<'amino acid' | 'aminoglycoside' | 'anthracycline' | 'anthraquinone' | 'ansamycin' | 'chalkophore' | 'chromophore' | 'glycopeptide' | 'cyclic depsipeptide' | 'cyclic lipopeptide' | 'cyclic peptide' | 'heterocyclic' | 'imino sugar' | 'keto acid' | 'lipoglycopeptide' | 'lipopeptide' | 'macrolide' | 'non-polymer' | 'nucleoside' | 'oligopeptide' | 'oligosaccharide' | 'peptaibol' | 'peptide-like' | 'polycyclic' | 'polypeptide' | 'polysaccharide' | 'quinolone' | 'thiolactone' | 'thiopeptide' | 'siderophore' | 'unknown' | 'chalkophore, polypeptide'>(lstr),
|
||||
/**
|
||||
* A name of the molecule.
|
||||
*/
|
||||
@@ -2665,7 +2670,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* This data item contains the descriptor type.
|
||||
*/
|
||||
type: Aliased<'LINUCS' | 'Glycam Condensed Sequence' | 'Glycam Condensed Core Sequence' | 'WURCS'>(str),
|
||||
type: Aliased<'linucs' | 'glycam condensed sequence' | 'glycam condensed core sequence' | 'wurcs'>(lstr),
|
||||
/**
|
||||
* This data item contains the name of the program
|
||||
* or library used to compute the descriptor.
|
||||
@@ -2740,7 +2745,7 @@ export const mmCIF_Schema = {
|
||||
* A flag to indicate whether this monomer in the entity is
|
||||
* heterogeneous in sequence.
|
||||
*/
|
||||
hetero: Aliased<'no' | 'n' | 'yes' | 'y'>(str),
|
||||
hetero: Aliased<'no' | 'n' | 'yes' | 'y'>(lstr),
|
||||
/**
|
||||
* This data item is a pointer to _chem_comp.id in the CHEM_COMP
|
||||
* category.
|
||||
@@ -2812,7 +2817,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The chiral configuration of the first atom making the linkage.
|
||||
*/
|
||||
atom_stereo_config_1: Aliased<'R' | 'S' | 'N'>(str),
|
||||
atom_stereo_config_1: Aliased<'r' | 's' | 'n'>(lstr),
|
||||
/**
|
||||
* The atom identifier/name for the second atom making the linkage.
|
||||
*/
|
||||
@@ -2824,11 +2829,11 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The chiral configuration of the second atom making the linkage.
|
||||
*/
|
||||
atom_stereo_config_2: Aliased<'R' | 'S' | 'N'>(str),
|
||||
atom_stereo_config_2: Aliased<'r' | 's' | 'n'>(lstr),
|
||||
/**
|
||||
* The bond order target for the chemical linkage.
|
||||
*/
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str),
|
||||
value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Data items in the PDBX_ENTITY_BRANCH category specify the list
|
||||
@@ -2859,7 +2864,7 @@ export const mmCIF_Schema = {
|
||||
* A flag to indicate whether this monomer in the entity is
|
||||
* heterogeneous in sequence.
|
||||
*/
|
||||
hetero: Aliased<'no' | 'n' | 'yes' | 'y'>(str),
|
||||
hetero: Aliased<'no' | 'n' | 'yes' | 'y'>(lstr),
|
||||
/**
|
||||
* Pointer to _atom_site.label_asym_id.
|
||||
*/
|
||||
@@ -3332,15 +3337,15 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* A flag to indicate if the modeling is multi scale.
|
||||
*/
|
||||
multi_scale_flag: Aliased<'YES' | 'NO'>(str),
|
||||
multi_scale_flag: Aliased<'yes' | 'no'>(lstr),
|
||||
/**
|
||||
* A flag to indicate if the modeling is multi state.
|
||||
*/
|
||||
multi_state_flag: Aliased<'YES' | 'NO'>(str),
|
||||
multi_state_flag: Aliased<'yes' | 'no'>(lstr),
|
||||
/**
|
||||
* A flag to indicate if the modeling involves an ensemble ordered by time or other order.
|
||||
*/
|
||||
ordered_flag: Aliased<'YES' | 'NO'>(str),
|
||||
ordered_flag: Aliased<'yes' | 'no'>(lstr),
|
||||
/**
|
||||
* The file id corresponding to the script used in the modeling protocol step.
|
||||
* This data item is a pointer to _ihm_external_files.id in the IHM_EXTERNAL_FILES category.
|
||||
@@ -3629,7 +3634,7 @@ export const mmCIF_Schema = {
|
||||
* A flag that indicates whether the dataset is archived in
|
||||
* an IHM related database or elsewhere.
|
||||
*/
|
||||
database_hosted: Aliased<'YES' | 'NO'>(str),
|
||||
database_hosted: Aliased<'yes' | 'no'>(lstr),
|
||||
},
|
||||
/**
|
||||
* Category to define groups or collections of input datasets.
|
||||
@@ -4236,7 +4241,7 @@ export const mmCIF_Schema = {
|
||||
* whether the whole image is used or only a portion of it is used (by masking
|
||||
* or by other means) as restraint in the modeling.
|
||||
*/
|
||||
image_segment_flag: Aliased<'YES' | 'NO'>(str),
|
||||
image_segment_flag: Aliased<'yes' | 'no'>(lstr),
|
||||
/**
|
||||
* Number of 2D projections of the model used in the fitting.
|
||||
*/
|
||||
@@ -4389,7 +4394,7 @@ export const mmCIF_Schema = {
|
||||
* whether the whole SAS profile is used or only a portion of it is used
|
||||
* (by masking or by other means) as restraint in the modeling.
|
||||
*/
|
||||
profile_segment_flag: Aliased<'YES' | 'NO'>(str),
|
||||
profile_segment_flag: Aliased<'yes' | 'no'>(lstr),
|
||||
/**
|
||||
* The type of atoms in the model fit to the SAS data.
|
||||
*/
|
||||
@@ -4983,7 +4988,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The type of QA metric.
|
||||
*/
|
||||
type: Aliased<'zscore' | 'energy' | 'distance' | 'normalized score' | 'pLDDT' | 'PAE' | 'contact probability' | 'other'>(str),
|
||||
type: Aliased<'zscore' | 'energy' | 'distance' | 'normalized score' | 'pLDDT' | 'pLDDT in [0,1]' | 'pLDDT all-atom' | 'pLDDT all-atom in [0,1]' | 'PAE' | 'pTM' | 'ipTM' | 'contact probability' | 'other'>(str),
|
||||
/**
|
||||
* The mode of calculation of the QA metric.
|
||||
*/
|
||||
|
||||
89
src/mol-io/reader/nctraj/parser.ts
Normal file
89
src/mol-io/reader/nctraj/parser.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Task } from '../../../mol-task';
|
||||
import { Mutable } from '../../../mol-util/type-helpers';
|
||||
import { NetcdfReader } from '../../common/netcdf/reader';
|
||||
import { ReaderResult as Result } from '../result';
|
||||
|
||||
export interface NctrajFile {
|
||||
coordinates: number[][],
|
||||
velocities?: number[][],
|
||||
forces?: number[][],
|
||||
cell_lengths?: number[][],
|
||||
cell_angles?: number[][],
|
||||
time?: number[],
|
||||
timeOffset: number,
|
||||
deltaTime: number
|
||||
}
|
||||
|
||||
async function parseInternal(data: Uint8Array) {
|
||||
// http://ambermd.org/netcdf/nctraj.xhtml
|
||||
|
||||
const nc = new NetcdfReader(data);
|
||||
|
||||
const f: Mutable<NctrajFile> = {
|
||||
coordinates: [],
|
||||
time: [],
|
||||
timeOffset: 0,
|
||||
deltaTime: 1
|
||||
};
|
||||
|
||||
for (const c of nc.getDataVariable('coordinates')) f.coordinates.push(c);
|
||||
|
||||
if (nc.hasDataVariable('velocities')) {
|
||||
const velocities: number[][] = [];
|
||||
for (const v of nc.getDataVariable('velocities')) velocities.push(v);
|
||||
f.velocities = velocities;
|
||||
}
|
||||
|
||||
if (nc.hasDataVariable('forces')) {
|
||||
const forces: number[][] = [];
|
||||
for (const f of nc.getDataVariable('forces')) forces.push(f);
|
||||
f.forces = forces;
|
||||
}
|
||||
|
||||
if (nc.hasDataVariable('cell_lengths')) {
|
||||
const cell_lengths: number[][] = [];
|
||||
for (const l of nc.getDataVariable('cell_lengths')) cell_lengths.push(l);
|
||||
f.cell_lengths = cell_lengths;
|
||||
}
|
||||
|
||||
if (nc.hasDataVariable('cell_angles')) {
|
||||
const cell_angles: number[][] = [];
|
||||
for (const a of nc.getDataVariable('cell_angles')) cell_angles.push(a);
|
||||
f.cell_angles = cell_angles;
|
||||
}
|
||||
|
||||
if (nc.hasDataVariable('time')) {
|
||||
const time: number[] = [];
|
||||
for (const t of nc.getDataVariable('time')) time.push(t);
|
||||
f.time = time;
|
||||
}
|
||||
|
||||
if (f.time) {
|
||||
if (f.time.length >= 1) {
|
||||
f.timeOffset = f.time[0];
|
||||
}
|
||||
if (f.time.length >= 2) {
|
||||
f.deltaTime = f.time[1] - f.time[0];
|
||||
}
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
export function parseNctraj(data: Uint8Array) {
|
||||
return Task.create<Result<NctrajFile>>('Parse NCTRAJ', async ctx => {
|
||||
try {
|
||||
ctx.update({ canAbort: true, message: 'Parsing trajectory...' });
|
||||
const file = await parseInternal(data);
|
||||
return Result.success(file);
|
||||
} catch (e) {
|
||||
return Result.error('' + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
176
src/mol-io/reader/prmtop/parser.ts
Normal file
176
src/mol-io/reader/prmtop/parser.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Task, RuntimeContext } from '../../../mol-task';
|
||||
import { Tokenizer, TokenBuilder, Tokens } from '../common/text/tokenizer';
|
||||
import { ReaderResult as Result } from '../result';
|
||||
import { TokenColumnProvider as TokenColumn } from '../common/text/column/token';
|
||||
import { Column } from '../../../mol-data/db';
|
||||
import { Mutable } from '../../../mol-util/type-helpers';
|
||||
|
||||
// http://ambermd.org/prmtop.pdf
|
||||
// https://ambermd.org/FileFormats.php#topology
|
||||
|
||||
const Pointers = {
|
||||
'NATOM': '', 'NTYPES': '', 'NBONH': '', 'MBONA': '', 'NTHETH': '', 'MTHETA': '',
|
||||
'NPHIH': '', 'MPHIA': '', 'NHPARM': '', 'NPARM': '', 'NNB': '', 'NRES': '',
|
||||
'NBONA': '', 'NTHETA': '', 'NPHIA': '', 'NUMBND': '', 'NUMANG': '', 'NPTRA': '',
|
||||
'NATYP': '', 'NPHB': '', 'IFPERT': '', 'NBPER': '', 'NGPER': '', 'NDPER': '',
|
||||
'MBPER': '', 'MGPER': '', 'MDPER': '', 'IFBOX': '', 'NMXRS': '', 'IFCAP': '',
|
||||
'NUMEXTRA': '', 'NCOPY': '',
|
||||
};
|
||||
type PointerName = keyof typeof Pointers;
|
||||
const PointersNames = Object.keys(Pointers) as PointerName[];
|
||||
|
||||
export interface PrmtopFile {
|
||||
readonly version: string
|
||||
readonly title: ReadonlyArray<string>
|
||||
readonly pointers: Readonly<Record<PointerName, number>>
|
||||
readonly atomName: Column<string>
|
||||
readonly charge: Column<number>
|
||||
readonly mass: Column<number>
|
||||
readonly residueLabel: Column<string>
|
||||
readonly residuePointer: Column<number>
|
||||
readonly bondsIncHydrogen: Column<number>
|
||||
readonly bondsWithoutHydrogen: Column<number>
|
||||
readonly radii: Column<number>
|
||||
}
|
||||
|
||||
const { readLine, markLine, trim } = Tokenizer;
|
||||
|
||||
function State(tokenizer: Tokenizer, runtimeCtx: RuntimeContext) {
|
||||
return {
|
||||
tokenizer,
|
||||
runtimeCtx,
|
||||
};
|
||||
}
|
||||
type State = ReturnType<typeof State>
|
||||
|
||||
function handleTitle(state: State): string[] {
|
||||
const { tokenizer } = state;
|
||||
const title: string[] = [];
|
||||
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
if (tokenizer.data[tokenizer.position] === '%') break;
|
||||
const line = readLine(tokenizer).trim();
|
||||
if (line) title.push(line);
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
function handlePointers(state: State): Record<PointerName, number> {
|
||||
const { tokenizer } = state;
|
||||
|
||||
const pointers: Record<PointerName, number> = Object.create(null);
|
||||
PointersNames.forEach(name => { pointers[name] = 0; });
|
||||
|
||||
let curIdx = 0;
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
if (tokenizer.data[tokenizer.position] === '%') break;
|
||||
const line = readLine(tokenizer);
|
||||
|
||||
const n = Math.min(curIdx + 10, 32);
|
||||
for (let i = 0; curIdx < n; ++i, ++curIdx) {
|
||||
pointers[PointersNames[curIdx]] = parseInt(
|
||||
line.substring(i * 8, i * 8 + 8).trim()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return pointers;
|
||||
}
|
||||
|
||||
function handleTokens(state: State, count: number, countPerLine: number, itemSize: number): Tokens {
|
||||
const { tokenizer } = state;
|
||||
|
||||
const tokens = TokenBuilder.create(tokenizer.data, count * 2);
|
||||
|
||||
let curIdx = 0;
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
if (tokenizer.data[tokenizer.position] === '%') break;
|
||||
|
||||
tokenizer.tokenStart = tokenizer.position;
|
||||
const n = Math.min(curIdx + countPerLine, count);
|
||||
for (let i = 0; curIdx < n; ++i, ++curIdx) {
|
||||
const p = tokenizer.position;
|
||||
trim(tokenizer, tokenizer.position, tokenizer.position + itemSize);
|
||||
TokenBuilder.addUnchecked(tokens, tokenizer.tokenStart, tokenizer.tokenEnd);
|
||||
tokenizer.position = p + itemSize;
|
||||
}
|
||||
|
||||
markLine(tokenizer);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
async function parseInternal(data: string, ctx: RuntimeContext): Promise<Result<PrmtopFile>> {
|
||||
const t = Tokenizer(data);
|
||||
const state = State(t, ctx);
|
||||
|
||||
const result: Mutable<PrmtopFile> = Object.create(null);
|
||||
let prevPosition = 0;
|
||||
|
||||
while (t.tokenEnd < t.length) {
|
||||
if (t.position - prevPosition > 100000 && ctx.shouldUpdate) {
|
||||
prevPosition = t.position;
|
||||
await ctx.update({ current: t.position, max: t.length });
|
||||
}
|
||||
|
||||
const line = readLine(state.tokenizer).trim();
|
||||
if (line.startsWith('%VERSION')) {
|
||||
result.version = line.substring(8).trim();
|
||||
} else if (line.startsWith('%FLAG')) {
|
||||
const flag = line.substring(5).trim();
|
||||
const formatLine = readLine(state.tokenizer).trim();
|
||||
if (!formatLine.startsWith('%FORMAT')) throw new Error('expected %FORMAT');
|
||||
|
||||
if (flag === 'TITLE') {
|
||||
result.title = handleTitle(state);
|
||||
} else if (flag === 'POINTERS') {
|
||||
result.pointers = handlePointers(state);
|
||||
} else if (flag === 'ATOM_NAME') {
|
||||
const tokens = handleTokens(state, result.pointers['NATOM'], 20, 4);
|
||||
result.atomName = TokenColumn(tokens)(Column.Schema.str);
|
||||
} else if (flag === 'CHARGE') {
|
||||
const tokens = handleTokens(state, result.pointers['NATOM'], 5, 16);
|
||||
result.charge = TokenColumn(tokens)(Column.Schema.float);
|
||||
} else if (flag === 'MASS') {
|
||||
const tokens = handleTokens(state, result.pointers['NATOM'], 5, 16);
|
||||
result.mass = TokenColumn(tokens)(Column.Schema.float);
|
||||
} else if (flag === 'RESIDUE_LABEL') {
|
||||
const tokens = handleTokens(state, result.pointers['NRES'], 20, 4);
|
||||
result.residueLabel = TokenColumn(tokens)(Column.Schema.str);
|
||||
} else if (flag === 'RESIDUE_POINTER') {
|
||||
const tokens = handleTokens(state, result.pointers['NRES'], 10, 8);
|
||||
result.residuePointer = TokenColumn(tokens)(Column.Schema.int);
|
||||
} else if (flag === 'BONDS_INC_HYDROGEN') {
|
||||
const tokens = handleTokens(state, result.pointers['NBONH'] * 3, 10, 8);
|
||||
result.bondsIncHydrogen = TokenColumn(tokens)(Column.Schema.int);
|
||||
} else if (flag === 'BONDS_WITHOUT_HYDROGEN') {
|
||||
const tokens = handleTokens(state, result.pointers['NBONA'] * 3, 10, 8);
|
||||
result.bondsWithoutHydrogen = TokenColumn(tokens)(Column.Schema.int);
|
||||
} else if (flag === 'RADII') {
|
||||
const tokens = handleTokens(state, result.pointers['NATOM'], 5, 16);
|
||||
result.radii = TokenColumn(tokens)(Column.Schema.float);
|
||||
} else {
|
||||
while (t.tokenEnd < t.length) {
|
||||
if (t.data[t.position] === '%') break;
|
||||
markLine(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
export function parsePrmtop(data: string) {
|
||||
return Task.create<Result<PrmtopFile>>('Parse PRMTOP', async ctx => {
|
||||
return await parseInternal(data, ctx);
|
||||
});
|
||||
}
|
||||
303
src/mol-io/reader/top/parser.ts
Normal file
303
src/mol-io/reader/top/parser.ts
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Task, RuntimeContext } from '../../../mol-task';
|
||||
import { Tokenizer, TokenBuilder } from '../common/text/tokenizer';
|
||||
import { ReaderResult as Result } from '../result';
|
||||
import { TokenColumnProvider as TokenColumn } from '../common/text/column/token';
|
||||
import { Column, Table } from '../../../mol-data/db';
|
||||
import { Mutable } from '../../../mol-util/type-helpers';
|
||||
|
||||
// https://manual.gromacs.org/2021-current/reference-manual/file-formats.html#top
|
||||
|
||||
const AtomsSchema = {
|
||||
nr: Column.Schema.Int(),
|
||||
type: Column.Schema.Str(),
|
||||
resnr: Column.Schema.Int(),
|
||||
residu: Column.Schema.Str(),
|
||||
atom: Column.Schema.Str(),
|
||||
cgnr: Column.Schema.Int(),
|
||||
charge: Column.Schema.Float(),
|
||||
mass: Column.Schema.Float(),
|
||||
};
|
||||
|
||||
const BondsSchema = {
|
||||
ai: Column.Schema.Int(),
|
||||
aj: Column.Schema.Int(),
|
||||
};
|
||||
|
||||
const MoleculesSchema = {
|
||||
compound: Column.Schema.Str(),
|
||||
molCount: Column.Schema.Int(),
|
||||
};
|
||||
|
||||
type Compound = {
|
||||
atoms: Table<typeof AtomsSchema>
|
||||
bonds?: Table<typeof BondsSchema>
|
||||
}
|
||||
|
||||
export interface TopFile {
|
||||
readonly system: string
|
||||
readonly molecules: Table<typeof MoleculesSchema>
|
||||
readonly compounds: Record<string, Compound>
|
||||
}
|
||||
|
||||
const { readLine, markLine, skipWhitespace, markStart, eatValue, eatLine } = Tokenizer;
|
||||
|
||||
function State(tokenizer: Tokenizer, runtimeCtx: RuntimeContext) {
|
||||
return {
|
||||
tokenizer,
|
||||
runtimeCtx,
|
||||
};
|
||||
}
|
||||
type State = ReturnType<typeof State>
|
||||
|
||||
const reField = /\[ (.+) \]/;
|
||||
const reWhitespace = /\s+/;
|
||||
|
||||
function handleMoleculetype(state: State) {
|
||||
const { tokenizer } = state;
|
||||
|
||||
let molName: string | undefined = undefined;
|
||||
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
skipWhitespace(tokenizer);
|
||||
const c = tokenizer.data[tokenizer.position];
|
||||
if (c === '[') break;
|
||||
if (c === ';' || c === '*') {
|
||||
markLine(tokenizer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (molName !== undefined) throw new Error('more than one molName');
|
||||
|
||||
const line = readLine(tokenizer);
|
||||
molName = line.split(reWhitespace)[0];
|
||||
}
|
||||
|
||||
if (molName === undefined) throw new Error('missing molName');
|
||||
|
||||
return molName;
|
||||
}
|
||||
|
||||
function handleAtoms(state: State) {
|
||||
const { tokenizer } = state;
|
||||
|
||||
const nr = TokenBuilder.create(tokenizer.data, 64);
|
||||
const type = TokenBuilder.create(tokenizer.data, 64);
|
||||
const resnr = TokenBuilder.create(tokenizer.data, 64);
|
||||
const residu = TokenBuilder.create(tokenizer.data, 64);
|
||||
const atom = TokenBuilder.create(tokenizer.data, 64);
|
||||
const cgnr = TokenBuilder.create(tokenizer.data, 64);
|
||||
const charge = TokenBuilder.create(tokenizer.data, 64);
|
||||
const mass = TokenBuilder.create(tokenizer.data, 64);
|
||||
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
skipWhitespace(tokenizer);
|
||||
const c = tokenizer.data[tokenizer.position];
|
||||
if (c === '[') break;
|
||||
if (c === ';' || c === '*') {
|
||||
markLine(tokenizer);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < 8; ++j) {
|
||||
skipWhitespace(tokenizer);
|
||||
markStart(tokenizer);
|
||||
eatValue(tokenizer);
|
||||
|
||||
switch (j) {
|
||||
case 0: TokenBuilder.add(nr, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 1: TokenBuilder.add(type, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 2: TokenBuilder.add(resnr, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 3: TokenBuilder.add(residu, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 4: TokenBuilder.add(atom, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 5: TokenBuilder.add(cgnr, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 6: TokenBuilder.add(charge, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 7: TokenBuilder.add(mass, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
}
|
||||
}
|
||||
// ignore any extra columns
|
||||
markLine(tokenizer);
|
||||
}
|
||||
|
||||
return Table.ofColumns(AtomsSchema, {
|
||||
nr: TokenColumn(nr)(Column.Schema.int),
|
||||
type: TokenColumn(type)(Column.Schema.str),
|
||||
resnr: TokenColumn(resnr)(Column.Schema.int),
|
||||
residu: TokenColumn(residu)(Column.Schema.str),
|
||||
atom: TokenColumn(atom)(Column.Schema.str),
|
||||
cgnr: TokenColumn(cgnr)(Column.Schema.int),
|
||||
charge: TokenColumn(charge)(Column.Schema.float),
|
||||
mass: TokenColumn(mass)(Column.Schema.float),
|
||||
});
|
||||
}
|
||||
|
||||
function handleBonds(state: State) {
|
||||
const { tokenizer } = state;
|
||||
|
||||
const ai = TokenBuilder.create(tokenizer.data, 64);
|
||||
const aj = TokenBuilder.create(tokenizer.data, 64);
|
||||
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
skipWhitespace(tokenizer);
|
||||
const c = tokenizer.data[tokenizer.position];
|
||||
if (c === '[') break;
|
||||
if (c === ';' || c === '*') {
|
||||
markLine(tokenizer);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < 2; ++j) {
|
||||
skipWhitespace(tokenizer);
|
||||
markStart(tokenizer);
|
||||
eatValue(tokenizer);
|
||||
|
||||
switch (j) {
|
||||
case 0: TokenBuilder.add(ai, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 1: TokenBuilder.add(aj, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
}
|
||||
}
|
||||
// ignore any extra columns
|
||||
markLine(tokenizer);
|
||||
}
|
||||
|
||||
return Table.ofColumns(BondsSchema, {
|
||||
ai: TokenColumn(ai)(Column.Schema.int),
|
||||
aj: TokenColumn(aj)(Column.Schema.int),
|
||||
});
|
||||
}
|
||||
|
||||
function handleSystem(state: State) {
|
||||
const { tokenizer } = state;
|
||||
|
||||
let system: string | undefined = undefined;
|
||||
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
skipWhitespace(tokenizer);
|
||||
const c = tokenizer.data[tokenizer.position];
|
||||
if (c === '[') break;
|
||||
if (c === ';' || c === '*') {
|
||||
markLine(tokenizer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (system !== undefined) throw new Error('more than one system');
|
||||
system = readLine(tokenizer).trim();
|
||||
}
|
||||
|
||||
if (system === undefined) throw new Error('missing system');
|
||||
|
||||
return system;
|
||||
}
|
||||
|
||||
function handleMolecules(state: State) {
|
||||
const { tokenizer } = state;
|
||||
|
||||
const compound = TokenBuilder.create(tokenizer.data, 64);
|
||||
const molCount = TokenBuilder.create(tokenizer.data, 64);
|
||||
|
||||
while (tokenizer.tokenEnd < tokenizer.length) {
|
||||
skipWhitespace(tokenizer);
|
||||
if (tokenizer.position >= tokenizer.length) break;
|
||||
|
||||
const c = tokenizer.data[tokenizer.position];
|
||||
if (c === '[') break;
|
||||
if (c === ';' || c === '*') {
|
||||
markLine(tokenizer);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < 2; ++j) {
|
||||
skipWhitespace(tokenizer);
|
||||
markStart(tokenizer);
|
||||
eatValue(tokenizer);
|
||||
|
||||
switch (j) {
|
||||
case 0: TokenBuilder.add(compound, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
case 1: TokenBuilder.add(molCount, tokenizer.tokenStart, tokenizer.tokenEnd); break;
|
||||
}
|
||||
}
|
||||
// ignore any extra columns
|
||||
eatLine(tokenizer);
|
||||
markStart(tokenizer);
|
||||
}
|
||||
|
||||
return Table.ofColumns(MoleculesSchema, {
|
||||
compound: TokenColumn(compound)(Column.Schema.str),
|
||||
molCount: TokenColumn(molCount)(Column.Schema.int),
|
||||
});
|
||||
}
|
||||
|
||||
async function parseInternal(data: string, ctx: RuntimeContext): Promise<Result<TopFile>> {
|
||||
const t = Tokenizer(data);
|
||||
const state = State(t, ctx);
|
||||
|
||||
const result: Mutable<TopFile> = Object.create(null);
|
||||
let prevPosition = 0;
|
||||
|
||||
result.compounds = {};
|
||||
let currentCompound: Partial<Compound> = {};
|
||||
let currentMolName = '';
|
||||
|
||||
function addMol() {
|
||||
if (currentMolName && currentCompound.atoms) {
|
||||
result.compounds[currentMolName] = currentCompound as Compound;
|
||||
currentCompound = {};
|
||||
currentMolName = '';
|
||||
}
|
||||
}
|
||||
|
||||
while (t.tokenEnd < t.length) {
|
||||
if (t.position - prevPosition > 100000 && ctx.shouldUpdate) {
|
||||
prevPosition = t.position;
|
||||
await ctx.update({ current: t.position, max: t.length });
|
||||
}
|
||||
|
||||
const line = readLine(state.tokenizer).trim();
|
||||
|
||||
if (!line || line[0] === '*' || line[0] === ';') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.startsWith('#include')) {
|
||||
throw new Error('#include statements not allowed');
|
||||
}
|
||||
|
||||
if (line.startsWith('[')) {
|
||||
const fieldMatch = line.match(reField);
|
||||
if (fieldMatch === null) throw new Error('expected field name');
|
||||
|
||||
const fieldName = fieldMatch[1];
|
||||
if (fieldName === 'moleculetype') {
|
||||
addMol();
|
||||
currentMolName = handleMoleculetype(state);
|
||||
} else if (fieldName === 'atoms') {
|
||||
currentCompound.atoms = handleAtoms(state);
|
||||
} else if (fieldName === 'bonds') {
|
||||
currentCompound.bonds = handleBonds(state);
|
||||
} else if (fieldName === 'system') {
|
||||
result.system = handleSystem(state);
|
||||
} else if (fieldName === 'molecules') {
|
||||
addMol(); // add the last compound
|
||||
result.molecules = handleMolecules(state);
|
||||
} else {
|
||||
while (t.tokenEnd < t.length) {
|
||||
if (t.data[t.position] === '[') break;
|
||||
markLine(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
export function parseTop(data: string) {
|
||||
return Task.create<Result<TopFile>>('Parse TOP', async ctx => {
|
||||
return await parseInternal(data, ctx);
|
||||
});
|
||||
}
|
||||
157
src/mol-io/reader/trr/parser.ts
Normal file
157
src/mol-io/reader/trr/parser.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Adapted from NGL.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Task } from '../../../mol-task';
|
||||
import { ReaderResult as Result } from '../result';
|
||||
|
||||
export interface TrrFile {
|
||||
frames: { count: number, x: Float32Array, y: Float32Array, z: Float32Array }[],
|
||||
boxes: number[][],
|
||||
times: number[],
|
||||
timeOffset: number,
|
||||
deltaTime: number
|
||||
}
|
||||
|
||||
async function parseInternal(data: Uint8Array) {
|
||||
// https://github.com/gromacs/gromacs/blob/master/src/gromacs/fileio/trrio.cpp
|
||||
|
||||
const dv = new DataView(data.buffer);
|
||||
|
||||
const f: TrrFile = {
|
||||
frames: [],
|
||||
boxes: [],
|
||||
times: [],
|
||||
timeOffset: 0,
|
||||
deltaTime: 0
|
||||
};
|
||||
const coordinates = f.frames;
|
||||
const boxes = f.boxes;
|
||||
const times = f.times;
|
||||
|
||||
let offset = 0;
|
||||
|
||||
while (true) {
|
||||
// const magicnum = dv.getInt32(offset)
|
||||
// const i1 = dv.getFloat32(offset + 4)
|
||||
offset += 8;
|
||||
|
||||
const versionSize = dv.getInt32(offset);
|
||||
offset += 4;
|
||||
offset += versionSize;
|
||||
|
||||
// const irSize = dv.getInt32(offset)
|
||||
// const eSize = dv.getInt32(offset + 4)
|
||||
const boxSize = dv.getInt32(offset + 8);
|
||||
const virSize = dv.getInt32(offset + 12);
|
||||
const presSize = dv.getInt32(offset + 16);
|
||||
// const topSize = dv.getInt32(offset + 20)
|
||||
// const symSize = dv.getInt32(offset + 24)
|
||||
const coordSize = dv.getInt32(offset + 28);
|
||||
const velocitySize = dv.getInt32(offset + 32);
|
||||
const forceSize = dv.getInt32(offset + 36);
|
||||
const natoms = dv.getInt32(offset + 40);
|
||||
// const step = dv.getInt32(offset + 44)
|
||||
// const nre = dv.getInt32(offset + 48)
|
||||
offset += 52;
|
||||
|
||||
const floatSize = boxSize / 9;
|
||||
const natoms3 = natoms * 3;
|
||||
|
||||
// let lambda
|
||||
if (floatSize === 8) {
|
||||
times.push(dv.getFloat64(offset));
|
||||
// lambda = dv.getFloat64(offset + 8)
|
||||
} else {
|
||||
times.push(dv.getFloat32(offset));
|
||||
// lambda = dv.getFloat32(offset + 4)
|
||||
}
|
||||
offset += 2 * floatSize;
|
||||
|
||||
if (boxSize) {
|
||||
const box = new Float32Array(9);
|
||||
if (floatSize === 8) {
|
||||
for (let i = 0; i < 9; ++i) {
|
||||
box[i] = dv.getFloat64(offset) * 10;
|
||||
offset += 8;
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < 9; ++i) {
|
||||
box[i] = dv.getFloat32(offset) * 10;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
boxes.push(box as unknown as number[]);
|
||||
}
|
||||
|
||||
// ignore, unused
|
||||
offset += virSize;
|
||||
|
||||
// ignore, unused
|
||||
offset += presSize;
|
||||
|
||||
if (coordSize) {
|
||||
const x = new Float32Array(natoms);
|
||||
const y = new Float32Array(natoms);
|
||||
const z = new Float32Array(natoms);
|
||||
if (floatSize === 8) {
|
||||
for (let i = 0; i < natoms; ++i) {
|
||||
x[i] = dv.getFloat64(offset) * 10;
|
||||
y[i] = dv.getFloat64(offset + 8) * 10;
|
||||
z[i] = dv.getFloat64(offset + 16) * 10;
|
||||
offset += 24;
|
||||
}
|
||||
} else {
|
||||
const tmp = new Uint32Array(data.buffer, offset, natoms3);
|
||||
for (let i = 0; i < natoms3; ++i) {
|
||||
const value = tmp[i];
|
||||
tmp[i] = (
|
||||
((value & 0xFF) << 24) | ((value & 0xFF00) << 8) |
|
||||
((value >> 8) & 0xFF00) | ((value >> 24) & 0xFF)
|
||||
);
|
||||
}
|
||||
const frameCoords = new Float32Array(data.buffer, offset, natoms3);
|
||||
for (let i = 0; i < natoms; ++i) {
|
||||
x[i] = frameCoords[i * 3] * 10;
|
||||
y[i] = frameCoords[i * 3 + 1] * 10;
|
||||
z[i] = frameCoords[i * 3 + 2] * 10;
|
||||
offset += 12;
|
||||
}
|
||||
}
|
||||
coordinates.push({ count: natoms, x, y, z });
|
||||
}
|
||||
|
||||
// ignore, unused
|
||||
offset += velocitySize;
|
||||
|
||||
// ignore, unused
|
||||
offset += forceSize;
|
||||
|
||||
if (offset >= data.byteLength) break;
|
||||
}
|
||||
|
||||
if (times.length >= 1) {
|
||||
f.timeOffset = times[0];
|
||||
}
|
||||
if (times.length >= 2) {
|
||||
f.deltaTime = times[1] - times[0];
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
export function parseTrr(data: Uint8Array) {
|
||||
return Task.create<Result<TrrFile>>('Parse TRR', async ctx => {
|
||||
try {
|
||||
ctx.update({ canAbort: true, message: 'Parsing trajectory...' });
|
||||
const file = await parseInternal(data);
|
||||
return Result.success(file);
|
||||
} catch (e) {
|
||||
return Result.error('' + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import { Tensor } from '../../../mol-math/linear-algebra';
|
||||
import { Encoder as EncoderBase } from '../encoder';
|
||||
import { ArrayEncoder, ArrayEncoding } from '../../common/binary-cif';
|
||||
import { BinaryEncodingProvider } from './encoder/binary';
|
||||
import { assertUnreachable } from '../../../mol-util/type-helpers';
|
||||
|
||||
// TODO: support for "coordinate fields", make "coordinate precision" a parameter of the encoder
|
||||
// TODO: automatically detect "precision" of floating point arrays.
|
||||
@@ -324,7 +325,7 @@ function cifFieldsFromTableSchema(schema: Table.Schema) {
|
||||
} else if (t.valueType === 'tensor') {
|
||||
fields.push(...getTensorDefinitions(k, t.space));
|
||||
} else {
|
||||
throw new Error(`Unknown valueType ${t.valueType}`);
|
||||
assertUnreachable(t.valueType);
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
|
||||
@@ -9,12 +9,14 @@ import { Writer } from './writer';
|
||||
import { Encoder, Category, Field } from './cif/encoder';
|
||||
import { ComponentAtom } from '../../mol-model-formats/structure/property/atoms/chem_comp';
|
||||
import { ComponentBond } from '../../mol-model-formats/structure/property/bonds/chem_comp';
|
||||
import { getElementIdx, isHydrogen } from '../../mol-model/structure/structure/unit/bonds/common';
|
||||
import { ElementSymbol } from '../../mol-model/structure/model/types';
|
||||
|
||||
interface Atom {
|
||||
Cartn_x: number,
|
||||
Cartn_y: number,
|
||||
Cartn_z: number,
|
||||
type_symbol: string,
|
||||
type_symbol: ElementSymbol,
|
||||
index: number
|
||||
}
|
||||
|
||||
@@ -109,11 +111,12 @@ export abstract class LigandEncoder implements Encoder<string> {
|
||||
const key = it.move();
|
||||
|
||||
const lai = label_atom_id.value(key, data, index) as string;
|
||||
const ts = type_symbol.value(key, data, index) as string;
|
||||
if (this.skipHydrogen(ts)) {
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
// ignore all alternate locations after the first
|
||||
if (atoms.has(lai)) continue;
|
||||
|
||||
const ts = type_symbol.value(key, data, index) as ElementSymbol;
|
||||
if (this.skipHydrogen(ts)) continue;
|
||||
|
||||
const a: { [k: string]: (string | number) } = {};
|
||||
|
||||
for (let _f = 0, _fl = fields.length; _f < _fl; _f++) {
|
||||
@@ -131,11 +134,15 @@ export abstract class LigandEncoder implements Encoder<string> {
|
||||
return atoms;
|
||||
}
|
||||
|
||||
protected skipHydrogen(type_symbol: string) {
|
||||
protected skipHydrogen(type_symbol: ElementSymbol) {
|
||||
if (this.hydrogens) {
|
||||
return false;
|
||||
}
|
||||
return type_symbol === 'H';
|
||||
return this.isHydrogen(type_symbol);
|
||||
}
|
||||
|
||||
protected isHydrogen(type_symbol: ElementSymbol) {
|
||||
return isHydrogen(getElementIdx(type_symbol));
|
||||
}
|
||||
|
||||
private getSortedFields<Ctx>(instance: Category.Instance<Ctx>, names: string[]) {
|
||||
|
||||
@@ -26,14 +26,27 @@ export class MolEncoder extends LigandEncoder {
|
||||
|
||||
const atomMap = this.componentAtomData.entries.get(name)!;
|
||||
const bondMap = this.componentBondData.entries.get(name)!;
|
||||
// happens for the unknown ligands (UNL)
|
||||
if (!atomMap) throw Error(`The Chemical Component Dictionary doesn't hold any atom data for ${name}`);
|
||||
|
||||
let bondCount = 0;
|
||||
let chiral = false;
|
||||
|
||||
// traverse once to determine all actually present atoms
|
||||
const atoms = this.getAtoms(instance, source);
|
||||
atoms.forEach((atom1, label_atom_id1) => {
|
||||
const { index: i1 } = atom1;
|
||||
const { charge, stereo_config } = atomMap.map.get(label_atom_id1)!;
|
||||
const { index: i1, type_symbol: type_symbol1 } = atom1;
|
||||
const atomMapData1 = atomMap.map.get(label_atom_id1);
|
||||
|
||||
if (!atomMapData1) {
|
||||
if (this.isHydrogen(type_symbol1)) {
|
||||
return;
|
||||
} else {
|
||||
throw Error(`Unknown atom ${label_atom_id1} for component ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
const { charge, stereo_config } = atomMapData1;
|
||||
StringBuilder.writePadLeft(ctab, atom1.Cartn_x.toFixed(4), 10);
|
||||
StringBuilder.writePadLeft(ctab, atom1.Cartn_y.toFixed(4), 10);
|
||||
StringBuilder.writePadLeft(ctab, atom1.Cartn_z.toFixed(4), 10);
|
||||
@@ -42,7 +55,7 @@ export class MolEncoder extends LigandEncoder {
|
||||
StringBuilder.writeSafe(ctab, ' 0');
|
||||
StringBuilder.writeIntegerPadLeft(ctab, this.mapCharge(charge), 3);
|
||||
StringBuilder.writeSafe(ctab, ' 0 0 0 0 0 0 0 0 0 0\n');
|
||||
if (stereo_config !== 'N') chiral = true;
|
||||
if (stereo_config !== 'n') chiral = true;
|
||||
|
||||
// no data for metal ions
|
||||
if (!bondMap?.map) return;
|
||||
@@ -50,8 +63,8 @@ export class MolEncoder extends LigandEncoder {
|
||||
const atom2 = atoms.get(label_atom_id2);
|
||||
if (!atom2) return;
|
||||
|
||||
const { index: i2, type_symbol: type_symbol2 } = atom2;
|
||||
if (i1 < i2 && !this.skipHydrogen(type_symbol2)) {
|
||||
const { index: i2 } = atom2;
|
||||
if (i1 < i2) {
|
||||
const { order } = bond;
|
||||
StringBuilder.writeIntegerPadLeft(bonds, i1 + 1, 3);
|
||||
StringBuilder.writeIntegerPadLeft(bonds, i2 + 1, 3);
|
||||
|
||||
@@ -29,21 +29,34 @@ export class Mol2Encoder extends LigandEncoder {
|
||||
const name = this.getName(instance, source);
|
||||
StringBuilder.writeSafe(this.builder, `# Name: ${name}\n# Created by ${this.encoder}\n\n`);
|
||||
|
||||
const atomMap = this.componentAtomData.entries.get(name)!;
|
||||
const bondMap = this.componentBondData.entries.get(name)!;
|
||||
// happens for the unknown ligands (UNL)
|
||||
if (!atomMap) throw Error(`The Chemical Component Dictionary doesn't hold any atom data for ${name}`);
|
||||
let bondCount = 0;
|
||||
|
||||
const atoms = this.getAtoms(instance, source);
|
||||
StringBuilder.writeSafe(a, '@<TRIPOS>ATOM\n');
|
||||
StringBuilder.writeSafe(b, '@<TRIPOS>BOND\n');
|
||||
atoms.forEach((atom1, label_atom_id1) => {
|
||||
const { index: i1 } = atom1;
|
||||
const { index: i1, type_symbol: type_symbol1 } = atom1;
|
||||
const atomMapData1 = atomMap.map.get(label_atom_id1);
|
||||
|
||||
if (!atomMapData1) {
|
||||
if (this.isHydrogen(type_symbol1)) {
|
||||
return;
|
||||
} else {
|
||||
throw Error(`Unknown atom ${label_atom_id1} for component ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (bondMap?.map) {
|
||||
bondMap.map.get(label_atom_id1)!.forEach((bond, label_atom_id2) => {
|
||||
const atom2 = atoms.get(label_atom_id2);
|
||||
if (!atom2) return;
|
||||
|
||||
const { index: i2, type_symbol: type_symbol2 } = atom2;
|
||||
if (i1 < i2 && !this.skipHydrogen(type_symbol2)) {
|
||||
const { index: i2 } = atom2;
|
||||
if (i1 < i2) {
|
||||
const { order, flags } = bond;
|
||||
const ar = BondType.is(BondType.Flag.Aromatic, flags);
|
||||
StringBuilder.writeSafe(b, `${++bondCount} ${i1 + 1} ${i2 + 1} ${ar ? 'ar' : order}`);
|
||||
@@ -52,7 +65,7 @@ export class Mol2Encoder extends LigandEncoder {
|
||||
});
|
||||
}
|
||||
|
||||
const sybyl = bondMap?.map ? this.mapToSybyl(label_atom_id1, atom1.type_symbol, bondMap) : atom1.type_symbol;
|
||||
const sybyl = bondMap?.map ? this.mapToSybyl(label_atom_id1, type_symbol1, bondMap) : type_symbol1;
|
||||
StringBuilder.writeSafe(a, `${i1 + 1} ${label_atom_id1} ${atom1.Cartn_x.toFixed(3)} ${atom1.Cartn_y.toFixed(3)} ${atom1.Cartn_z.toFixed(3)} ${sybyl} 1 ${name} 0.000\n`);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 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>
|
||||
@@ -26,7 +26,8 @@ export type DensityData = {
|
||||
transform: Mat4,
|
||||
field: Tensor,
|
||||
idField: Tensor,
|
||||
resolution: number
|
||||
resolution: number,
|
||||
maxRadius: number,
|
||||
}
|
||||
|
||||
export type DensityTextureData = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -21,12 +21,12 @@ export type GaussianDensityProps = typeof DefaultGaussianDensityProps
|
||||
|
||||
export type GaussianDensityData = {
|
||||
radiusFactor: number
|
||||
resolution: number
|
||||
} & DensityData
|
||||
|
||||
export type GaussianDensityTextureData = {
|
||||
radiusFactor: number
|
||||
resolution: number
|
||||
maxRadius: number
|
||||
} & DensityTextureData
|
||||
|
||||
export function computeGaussianDensity(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -129,5 +129,5 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position
|
||||
Mat4.fromScaling(transform, Vec3.create(resolution, resolution, resolution));
|
||||
Mat4.setTranslation(transform, expandedBox.min);
|
||||
|
||||
return { field, idField, transform, radiusFactor: 1, resolution };
|
||||
return { field, idField, transform, radiusFactor: 1, resolution, maxRadius };
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Michael Krone <michael.krone@uni-tuebingen.de>
|
||||
@@ -70,12 +70,12 @@ export function GaussianDensityGPU(position: PositionData, box: Box3D, radius: (
|
||||
// it's faster than texture3d
|
||||
// console.time('GaussianDensityTexture2d')
|
||||
const tmpTexture = getTexture('tmp', webgl, 'image-uint8', 'rgba', 'ubyte', 'linear');
|
||||
const { scale, bbox, texture, gridDim, gridTexDim, radiusFactor, resolution } = calcGaussianDensityTexture2d(webgl, position, box, radius, false, props, tmpTexture);
|
||||
const { scale, bbox, texture, gridDim, gridTexDim, radiusFactor, resolution, maxRadius } = calcGaussianDensityTexture2d(webgl, position, box, radius, false, props, tmpTexture);
|
||||
// webgl.waitForGpuCommandsCompleteSync()
|
||||
// console.timeEnd('GaussianDensityTexture2d')
|
||||
const { field, idField } = fieldFromTexture2d(webgl, texture, gridDim, gridTexDim);
|
||||
|
||||
return { field, idField, transform: getTransform(scale, bbox), radiusFactor, resolution };
|
||||
return { field, idField, transform: getTransform(scale, bbox), radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
export function GaussianDensityTexture(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, oldTexture?: Texture): GaussianDensityTextureData {
|
||||
@@ -92,8 +92,8 @@ export function GaussianDensityTexture3d(webgl: WebGLContext, position: Position
|
||||
return finalizeGaussianDensityTexture(calcGaussianDensityTexture3d(webgl, position, box, radius, props, oldTexture));
|
||||
}
|
||||
|
||||
function finalizeGaussianDensityTexture({ texture, scale, bbox, gridDim, gridTexDim, gridTexScale, radiusFactor, resolution }: _GaussianDensityTextureData): GaussianDensityTextureData {
|
||||
return { transform: getTransform(scale, bbox), texture, bbox, gridDim, gridTexDim, gridTexScale, radiusFactor, resolution };
|
||||
function finalizeGaussianDensityTexture({ texture, scale, bbox, gridDim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius }: _GaussianDensityTextureData): GaussianDensityTextureData {
|
||||
return { transform: getTransform(scale, bbox), texture, bbox, gridDim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
function getTransform(scale: Vec3, bbox: Box3D) {
|
||||
@@ -114,6 +114,7 @@ type _GaussianDensityTextureData = {
|
||||
gridTexScale: Vec2
|
||||
radiusFactor: number
|
||||
resolution: number
|
||||
maxRadius: number
|
||||
}
|
||||
|
||||
function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, powerOfTwo: boolean, props: GaussianDensityProps, texture?: Texture): _GaussianDensityTextureData {
|
||||
@@ -198,7 +199,7 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
|
||||
|
||||
// printTexture(webgl, minDistTex, 0.75);
|
||||
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim, gridTexScale, radiusFactor, resolution };
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, texture?: Texture): _GaussianDensityTextureData {
|
||||
@@ -254,7 +255,7 @@ function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionDat
|
||||
setupGroupIdRendering(webgl, renderable);
|
||||
render(texture, false);
|
||||
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim: dim, gridTexScale, radiusFactor, resolution };
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim: dim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Fred Ludlow <fred.ludlow@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -370,5 +370,5 @@ export async function calcMolecularSurface(ctx: RuntimeContext, position: Requir
|
||||
Mat4.fromScaling(transform, Vec3.create(resolution, resolution, resolution));
|
||||
Mat4.setTranslation(transform, expandedBox.min);
|
||||
// console.log({ field, idField, transform, updateChunk })
|
||||
return { field, idField, transform, resolution };
|
||||
return { field, idField, transform, resolution, maxRadius };
|
||||
}
|
||||
@@ -32,7 +32,9 @@ namespace Box3D {
|
||||
|
||||
/** Get box from sphere, uses extrema if available */
|
||||
export function fromSphere3D(out: Box3D, sphere: Sphere3D): Box3D {
|
||||
if (Sphere3D.hasExtrema(sphere)) return fromVec3Array(out, sphere.extrema);
|
||||
if (Sphere3D.hasExtrema(sphere) && sphere.extrema.length >= 14) { // 14 extrema with coarse boundary helper
|
||||
return fromVec3Array(out, sphere.extrema);
|
||||
}
|
||||
const r = Vec3.create(sphere.radius, sphere.radius, sphere.radius);
|
||||
Vec3.sub(out.min, sphere.center, r);
|
||||
Vec3.add(out.max, sphere.center, r);
|
||||
|
||||
@@ -212,19 +212,26 @@ namespace Sphere3D {
|
||||
Axes3D.scale(axes, Axes3D.normalize(axes, axes), delta);
|
||||
|
||||
setExtrema(out, sphere.extrema.map(e => {
|
||||
Vec3.sub(tmpDir, e, sphere.center);
|
||||
const out = Vec3.clone(e);
|
||||
Vec3.normalize(tmpDir, Vec3.sub(tmpDir, e, sphere.center));
|
||||
const o = Vec3.clone(e);
|
||||
|
||||
const sA = Vec3.dot(tmpDir, axes.dirA) < 0 ? -1 : 1;
|
||||
Vec3.scaleAndAdd(out, out, axes.dirA, sA);
|
||||
Vec3.scaleAndAdd(o, o, axes.dirA, sA);
|
||||
|
||||
const sB = Vec3.dot(tmpDir, axes.dirB) < 0 ? -1 : 1;
|
||||
Vec3.scaleAndAdd(out, out, axes.dirB, sB);
|
||||
Vec3.scaleAndAdd(o, o, axes.dirB, sB);
|
||||
|
||||
const sC = Vec3.dot(tmpDir, axes.dirC) < 0 ? -1 : 1;
|
||||
Vec3.scaleAndAdd(out, out, axes.dirC, sC);
|
||||
Vec3.scaleAndAdd(o, o, axes.dirC, sC);
|
||||
|
||||
return out;
|
||||
if (Vec3.distance(out.center, o) > out.radius) {
|
||||
if (sphere.extrema.length >= 14) { // 14 extrema with coarse boundary helper
|
||||
Vec3.normalize(tmpDir, Vec3.sub(tmpDir, o, sphere.center));
|
||||
}
|
||||
Vec3.scaleAndAdd(o, out.center, tmpDir, out.radius);
|
||||
}
|
||||
|
||||
return o;
|
||||
}));
|
||||
}
|
||||
return out;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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>
|
||||
@@ -45,15 +45,6 @@ function findHierarchyOffsets(atom_site: AtomSite) {
|
||||
return { residues, chains };
|
||||
}
|
||||
|
||||
function substUndefinedColumn<T extends Table<any>>(table: T, a: keyof T, b: keyof T) {
|
||||
if (!(table as any)[a].isDefined) {
|
||||
(table as any)[a] = (table as any)[b];
|
||||
}
|
||||
if (!(table as any)[b].isDefined) {
|
||||
(table as any)[b] = (table as any)[a];
|
||||
}
|
||||
}
|
||||
|
||||
function createHierarchyData(atom_site: AtomSite, sourceIndex: Column<number>, offsets: { residues: ArrayLike<number>, chains: ArrayLike<number> }): AtomicData {
|
||||
const atoms = Table.ofColumns(AtomsSchema, {
|
||||
type_symbol: Column.ofArray({ array: Column.mapToArray(atom_site.type_symbol, ElementSymbol), schema: Column.Schema.Aliased<ElementSymbol>(Column.Schema.str) }),
|
||||
@@ -87,12 +78,6 @@ function createHierarchyData(atom_site: AtomSite, sourceIndex: Column<number>, o
|
||||
Table.columnToArray(residues, 'label_seq_id', Int32Array);
|
||||
Table.columnToArray(residues, 'auth_seq_id', Int32Array);
|
||||
|
||||
// Fix possibly missing auth_/label_ columns
|
||||
substUndefinedColumn(atoms, 'label_atom_id', 'auth_atom_id');
|
||||
substUndefinedColumn(atoms, 'label_comp_id', 'auth_comp_id');
|
||||
substUndefinedColumn(residues, 'label_seq_id', 'auth_seq_id');
|
||||
substUndefinedColumn(chains, 'label_asym_id', 'auth_asym_id');
|
||||
|
||||
return { atoms, residues, chains, atomSourceIndex: sourceIndex };
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ import { Entities, EntitySubtype } from '../../../mol-model/structure/model/prop
|
||||
import { getEntityType, getEntitySubtype } from '../../../mol-model/structure/model/types';
|
||||
import { ElementIndex, EntityIndex, Model } from '../../../mol-model/structure/model';
|
||||
import { BasicData, BasicSchema, Entity } from './schema';
|
||||
import { mmCIF_chemComp_schema } from '../../../mol-io/reader/cif/schema/mmcif-extras';
|
||||
|
||||
type ChemCompType = mmCIF_chemComp_schema['type']['T'];
|
||||
|
||||
export function getEntityData(data: BasicData): Entities {
|
||||
let entityData: Entity;
|
||||
@@ -96,7 +99,7 @@ export function getEntityData(data: BasicData): Entities {
|
||||
}
|
||||
|
||||
if (assignSubtype) {
|
||||
const chemCompType = new Map<string, string>();
|
||||
const chemCompType = new Map<string, ChemCompType>();
|
||||
if (data.chem_comp) {
|
||||
const { id, type } = data.chem_comp;
|
||||
for (let i = 0, il = data.chem_comp._rowCount; i < il; i++) {
|
||||
@@ -110,7 +113,7 @@ export function getEntityData(data: BasicData): Entities {
|
||||
const entityId = label_entity_id.value(i);
|
||||
if (!entityIds.has(entityId)) {
|
||||
const compId = label_comp_id.value(i);
|
||||
const compType = chemCompType.get(compId) || '';
|
||||
const compType = chemCompType.get(compId) || 'other';
|
||||
subtypes[getEntityIndex(entityId)] = getEntitySubtype(compId, compType);
|
||||
entityIds.add(entityId);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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>
|
||||
@@ -186,8 +186,6 @@ function splitTable<T extends Table<any>>(table: T, col: Column<number>) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function readIntegrative(ctx: RuntimeContext, data: BasicData, properties: CommonProperties, format: ModelFormat) {
|
||||
const entities = getEntityData(data);
|
||||
// when `atom_site.ihm_model_id` is undefined fall back to `atom_site.pdbx_PDB_model_num`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -7,6 +7,7 @@
|
||||
import { mmCIF_Schema } from '../../../mol-io/reader/cif/schema/mmcif';
|
||||
import { Table } from '../../../mol-data/db';
|
||||
import { mmCIF_chemComp_schema } from '../../../mol-io/reader/cif/schema/mmcif-extras';
|
||||
import { getNormalizedAtomSite } from './util';
|
||||
|
||||
// TODO split into conformation and hierarchy parts
|
||||
|
||||
@@ -68,7 +69,7 @@ export interface BasicData {
|
||||
pdbx_molecule: Molecule
|
||||
}
|
||||
|
||||
export function createBasic(data: Partial<BasicData>): BasicData {
|
||||
export function createBasic(data: Partial<BasicData>, normalize = false): BasicData {
|
||||
const basic = Object.create(null);
|
||||
for (const name of Object.keys(BasicSchema)) {
|
||||
if (name in data) {
|
||||
@@ -77,5 +78,8 @@ export function createBasic(data: Partial<BasicData>): BasicData {
|
||||
basic[name] = Table.ofUndefinedColumns(BasicSchema[name as keyof typeof BasicSchema], 0);
|
||||
}
|
||||
}
|
||||
if (normalize) {
|
||||
basic.atom_site = getNormalizedAtomSite(basic.atom_site);
|
||||
}
|
||||
return basic;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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 { BasicData } from './schema';
|
||||
import { Table } from '../../../mol-data/db';
|
||||
import { AtomSite, BasicData } from './schema';
|
||||
import { Column, Table } from '../../../mol-data/db';
|
||||
|
||||
export function getModelGroupName(model_id: number, data: BasicData) {
|
||||
const { ihm_model_group, ihm_model_group_link } = data;
|
||||
@@ -17,4 +17,28 @@ export function getModelGroupName(model_id: number, data: BasicData) {
|
||||
if (group) return group.name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function hasPresentValues(column: Column<any>) {
|
||||
for (let i = 0, il = column.rowCount; i < il; i++) {
|
||||
if (column.valueKind(i) === Column.ValueKind.Present) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function substUndefinedColumn<T extends Table<any>>(table: T, a: keyof T, b: keyof T) {
|
||||
if (!table[a].isDefined || !hasPresentValues(table[a])) table[a] = table[b];
|
||||
if (!table[b].isDefined || !hasPresentValues(table[b])) table[b] = table[a];
|
||||
}
|
||||
|
||||
/** Fix possibly missing auth_/label_ columns */
|
||||
export function getNormalizedAtomSite(atom_site: AtomSite) {
|
||||
const normalized = Table.ofColumns(atom_site._schema, atom_site);
|
||||
substUndefinedColumn(normalized, 'label_atom_id', 'auth_atom_id');
|
||||
substUndefinedColumn(normalized, 'label_comp_id', 'auth_comp_id');
|
||||
substUndefinedColumn(normalized, 'label_seq_id', 'auth_seq_id');
|
||||
substUndefinedColumn(normalized, 'label_asym_id', 'auth_asym_id');
|
||||
return normalized;
|
||||
}
|
||||
@@ -100,7 +100,7 @@ async function getModels(db: CifCore_Database, format: CifCoreFormat, ctx: Runti
|
||||
const element_symbol = new Array<string>(atomCount);
|
||||
for (let i = 0; i < atomCount; ++i) {
|
||||
// TODO can take as is if type_symbol not given?
|
||||
element_symbol[i] = guessElementSymbolString(label.value(i));
|
||||
element_symbol[i] = guessElementSymbolString(label.value(i), '');
|
||||
}
|
||||
typeSymbol = Column.ofStringArray(element_symbol);
|
||||
formalCharge = Column.Undefined(atomCount, Column.Schema.int);
|
||||
@@ -146,13 +146,13 @@ async function getModels(db: CifCore_Database, format: CifCoreFormat, ctx: Runti
|
||||
componentBuilder.setNames([['MOL', name || 'Unknown Molecule']]);
|
||||
componentBuilder.add('MOL', 0);
|
||||
|
||||
const basics = createBasic({
|
||||
const basic = createBasic({
|
||||
entity: entityBuilder.getEntityTable(),
|
||||
chem_comp: componentBuilder.getChemCompTable(),
|
||||
atom_site
|
||||
});
|
||||
|
||||
const models = await createModels(basics, format, ctx);
|
||||
const models = await createModels(basic, format, ctx);
|
||||
|
||||
if (models.frameCount > 0) {
|
||||
const first = models.representative;
|
||||
|
||||
@@ -9,6 +9,7 @@ import { WaterNames, PolymerNames } from '../../../mol-model/structure/model/typ
|
||||
import { SetUtils } from '../../../mol-util/set';
|
||||
import { BasicSchema } from '../basic/schema';
|
||||
import { mmCIF_chemComp_schema } from '../../../mol-io/reader/cif/schema/mmcif-extras';
|
||||
import { SaccharideCompIdMap } from '../../../mol-model/structure/structure/carbohydrates/constants';
|
||||
|
||||
type Component = Table.Row<Pick<mmCIF_chemComp_schema, 'id' | 'name' | 'type'>>
|
||||
|
||||
@@ -30,54 +31,54 @@ const DnaAtomIdsList = [
|
||||
|
||||
/** Used to reduce false positives for atom name-based type guessing */
|
||||
const NonPolymerNames = new Set([
|
||||
'FMN', 'NCN', 'FNS', 'FMA', 'ATP', 'ADP', 'AMP', 'GTP', 'GDP', 'GMP' // Mononucleotides
|
||||
'FMN', 'NCN', 'FNS', 'FMA', 'ATP', 'ADP', 'AMP', 'GTP', 'GDP', 'GMP', // Mononucleotides
|
||||
]);
|
||||
|
||||
const StandardComponents = (function () {
|
||||
const map = new Map<string, Component>();
|
||||
const components: Component[] = [
|
||||
{ id: 'HIS', name: 'HISTIDINE', type: 'L-peptide linking' },
|
||||
{ id: 'ARG', name: 'ARGININE', type: 'L-peptide linking' },
|
||||
{ id: 'LYS', name: 'LYSINE', type: 'L-peptide linking' },
|
||||
{ id: 'ILE', name: 'ISOLEUCINE', type: 'L-peptide linking' },
|
||||
{ id: 'PHE', name: 'PHENYLALANINE', type: 'L-peptide linking' },
|
||||
{ id: 'LEU', name: 'LEUCINE', type: 'L-peptide linking' },
|
||||
{ id: 'TRP', name: 'TRYPTOPHAN', type: 'L-peptide linking' },
|
||||
{ id: 'ALA', name: 'ALANINE', type: 'L-peptide linking' },
|
||||
{ id: 'MET', name: 'METHIONINE', type: 'L-peptide linking' },
|
||||
{ id: 'CYS', name: 'CYSTEINE', type: 'L-peptide linking' },
|
||||
{ id: 'ASN', name: 'ASPARAGINE', type: 'L-peptide linking' },
|
||||
{ id: 'VAL', name: 'VALINE', type: 'L-peptide linking' },
|
||||
{ id: 'HIS', name: 'HISTIDINE', type: 'l-peptide linking' },
|
||||
{ id: 'ARG', name: 'ARGININE', type: 'l-peptide linking' },
|
||||
{ id: 'LYS', name: 'LYSINE', type: 'l-peptide linking' },
|
||||
{ id: 'ILE', name: 'ISOLEUCINE', type: 'l-peptide linking' },
|
||||
{ id: 'PHE', name: 'PHENYLALANINE', type: 'l-peptide linking' },
|
||||
{ id: 'LEU', name: 'LEUCINE', type: 'l-peptide linking' },
|
||||
{ id: 'TRP', name: 'TRYPTOPHAN', type: 'l-peptide linking' },
|
||||
{ id: 'ALA', name: 'ALANINE', type: 'l-peptide linking' },
|
||||
{ id: 'MET', name: 'METHIONINE', type: 'l-peptide linking' },
|
||||
{ id: 'CYS', name: 'CYSTEINE', type: 'l-peptide linking' },
|
||||
{ id: 'ASN', name: 'ASPARAGINE', type: 'l-peptide linking' },
|
||||
{ id: 'VAL', name: 'VALINE', type: 'l-peptide linking' },
|
||||
{ id: 'GLY', name: 'GLYCINE', type: 'peptide linking' },
|
||||
{ id: 'SER', name: 'SERINE', type: 'L-peptide linking' },
|
||||
{ id: 'GLN', name: 'GLUTAMINE', type: 'L-peptide linking' },
|
||||
{ id: 'TYR', name: 'TYROSINE', type: 'L-peptide linking' },
|
||||
{ id: 'ASP', name: 'ASPARTIC ACID', type: 'L-peptide linking' },
|
||||
{ id: 'GLU', name: 'GLUTAMIC ACID', type: 'L-peptide linking' },
|
||||
{ id: 'THR', name: 'THREONINE', type: 'L-peptide linking' },
|
||||
{ id: 'PRO', name: 'PROLINE', type: 'L-peptide linking' },
|
||||
{ id: 'SEC', name: 'SELENOCYSTEINE', type: 'L-peptide linking' },
|
||||
{ id: 'PYL', name: 'PYRROLYSINE', type: 'L-peptide linking' },
|
||||
{ id: 'SER', name: 'SERINE', type: 'l-peptide linking' },
|
||||
{ id: 'GLN', name: 'GLUTAMINE', type: 'l-peptide linking' },
|
||||
{ id: 'TYR', name: 'TYROSINE', type: 'l-peptide linking' },
|
||||
{ id: 'ASP', name: 'ASPARTIC ACID', type: 'l-peptide linking' },
|
||||
{ id: 'GLU', name: 'GLUTAMIC ACID', type: 'l-peptide linking' },
|
||||
{ id: 'THR', name: 'THREONINE', type: 'l-peptide linking' },
|
||||
{ id: 'PRO', name: 'PROLINE', type: 'l-peptide linking' },
|
||||
{ id: 'SEC', name: 'SELENOCYSTEINE', type: 'l-peptide linking' },
|
||||
{ id: 'PYL', name: 'PYRROLYSINE', type: 'l-peptide linking' },
|
||||
|
||||
{ id: 'MSE', name: 'SELENOMETHIONINE', type: 'L-peptide linking' },
|
||||
{ id: 'SEP', name: 'PHOSPHOSERINE', type: 'L-peptide linking' },
|
||||
{ id: 'TPO', name: 'PHOSPHOTHREONINE', type: 'L-peptide linking' },
|
||||
{ id: 'PTR', name: 'O-PHOSPHOTYROSINE', type: 'L-peptide linking' },
|
||||
{ id: 'PCA', name: 'PYROGLUTAMIC ACID', type: 'L-peptide linking' },
|
||||
{ id: 'MSE', name: 'SELENOMETHIONINE', type: 'l-peptide linking' },
|
||||
{ id: 'SEP', name: 'PHOSPHOSERINE', type: 'l-peptide linking' },
|
||||
{ id: 'TPO', name: 'PHOSPHOTHREONINE', type: 'l-peptide linking' },
|
||||
{ id: 'PTR', name: 'O-PHOSPHOTYROSINE', type: 'l-peptide linking' },
|
||||
{ id: 'PCA', name: 'PYROGLUTAMIC ACID', type: 'l-peptide linking' },
|
||||
|
||||
{ id: 'A', name: 'ADENOSINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },
|
||||
{ id: 'C', name: 'CYTIDINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },
|
||||
{ id: 'T', name: 'THYMIDINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },
|
||||
{ id: 'G', name: 'GUANOSINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },
|
||||
{ id: 'I', name: 'INOSINIC ACID', type: 'RNA linking' },
|
||||
{ id: 'U', name: 'URIDINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },
|
||||
{ id: 'A', name: 'ADENOSINE-5\'-MONOPHOSPHATE', type: 'rna linking' },
|
||||
{ id: 'C', name: 'CYTIDINE-5\'-MONOPHOSPHATE', type: 'rna linking' },
|
||||
{ id: 'T', name: 'THYMIDINE-5\'-MONOPHOSPHATE', type: 'rna linking' },
|
||||
{ id: 'G', name: 'GUANOSINE-5\'-MONOPHOSPHATE', type: 'rna linking' },
|
||||
{ id: 'I', name: 'INOSINIC ACID', type: 'rna linking' },
|
||||
{ id: 'U', name: 'URIDINE-5\'-MONOPHOSPHATE', type: 'rna linking' },
|
||||
|
||||
{ id: 'DA', name: '2\'-DEOXYADENOSINE-5\'-MONOPHOSPHATE', type: 'DNA linking' },
|
||||
{ id: 'DC', name: '2\'-DEOXYCYTIDINE-5\'-MONOPHOSPHATE', type: 'DNA linking' },
|
||||
{ id: 'DT', name: 'THYMIDINE-5\'-MONOPHOSPHATE', type: 'DNA linking' },
|
||||
{ id: 'DG', name: '2\'-DEOXYGUANOSINE-5\'-MONOPHOSPHATE', type: 'DNA linking' },
|
||||
{ id: 'DI', name: '2\'-DEOXYINOSINE-5\'-MONOPHOSPHATE', type: 'DNA linking' },
|
||||
{ id: 'DU', name: '2\'-DEOXYURIDINE-5\'-MONOPHOSPHATE', type: 'DNA linking' },
|
||||
{ id: 'DA', name: '2\'-DEOXYADENOSINE-5\'-MONOPHOSPHATE', type: 'dna linking' },
|
||||
{ id: 'DC', name: '2\'-DEOXYCYTIDINE-5\'-MONOPHOSPHATE', type: 'dna linking' },
|
||||
{ id: 'DT', name: 'THYMIDINE-5\'-MONOPHOSPHATE', type: 'dna linking' },
|
||||
{ id: 'DG', name: '2\'-DEOXYGUANOSINE-5\'-MONOPHOSPHATE', type: 'dna linking' },
|
||||
{ id: 'DI', name: '2\'-DEOXYINOSINE-5\'-MONOPHOSPHATE', type: 'dna linking' },
|
||||
{ id: 'DU', name: '2\'-DEOXYURIDINE-5\'-MONOPHOSPHATE', type: 'dna linking' },
|
||||
];
|
||||
components.forEach(c => map.set(c.id, c));
|
||||
return map;
|
||||
@@ -86,12 +87,12 @@ const StandardComponents = (function () {
|
||||
const CharmmIonComponents = (function () {
|
||||
const map = new Map<string, Component>();
|
||||
const components: Component[] = [
|
||||
{ id: 'ZN2', name: 'ZINC ION', type: 'Ion' },
|
||||
{ id: 'SOD', name: 'SODIUM ION', type: 'Ion' },
|
||||
{ id: 'CES', name: 'CESIUM ION', type: 'Ion' },
|
||||
{ id: 'CLA', name: 'CHLORIDE ION', type: 'Ion' },
|
||||
{ id: 'CAL', name: 'CALCIUM ION', type: 'Ion' },
|
||||
{ id: 'POT', name: 'POTASSIUM ION', type: 'Ion' },
|
||||
{ id: 'ZN2', name: 'ZINC ION', type: 'ion' },
|
||||
{ id: 'SOD', name: 'SODIUM ION', type: 'ion' },
|
||||
{ id: 'CES', name: 'CESIUM ION', type: 'ion' },
|
||||
{ id: 'CLA', name: 'CHLORIDE ION', type: 'ion' },
|
||||
{ id: 'CAL', name: 'CALCIUM ION', type: 'ion' },
|
||||
{ id: 'POT', name: 'POTASSIUM ION', type: 'ion' },
|
||||
];
|
||||
components.forEach(c => map.set(c.id, c));
|
||||
return map;
|
||||
@@ -139,9 +140,9 @@ export class ComponentBuilder {
|
||||
if (this.hasAtomIds(atomIds, ProteinAtomIdsList)) {
|
||||
return 'peptide linking';
|
||||
} else if (this.hasAtomIds(atomIds, RnaAtomIdsList)) {
|
||||
return 'RNA linking';
|
||||
return 'rna linking';
|
||||
} else if (this.hasAtomIds(atomIds, DnaAtomIdsList)) {
|
||||
return 'DNA linking';
|
||||
return 'dna linking';
|
||||
} else {
|
||||
return 'other';
|
||||
}
|
||||
@@ -158,6 +159,8 @@ export class ComponentBuilder {
|
||||
this.set({ id: compId, name: 'WATER', type: 'non-polymer' });
|
||||
} else if (NonPolymerNames.has(compId.toUpperCase())) {
|
||||
this.set({ id: compId, name: this.namesMap.get(compId) || compId, type: 'non-polymer' });
|
||||
} else if (SaccharideCompIdMap.has(compId.toUpperCase())) {
|
||||
this.set({ id: compId, name: this.namesMap.get(compId) || compId, type: 'saccharide' });
|
||||
} else {
|
||||
const atomIds = this.getAtomIds(index);
|
||||
if (atomIds.size === 1 && CharmmIonComponents.has(compId)) {
|
||||
|
||||
@@ -53,13 +53,13 @@ async function getModels(cube: CubeFile, ctx: RuntimeContext) {
|
||||
componentBuilder.setNames([['MOL', 'Unknown Molecule']]);
|
||||
componentBuilder.add('MOL', 0);
|
||||
|
||||
const basics = createBasic({
|
||||
const basic = createBasic({
|
||||
entity: entityBuilder.getEntityTable(),
|
||||
chem_comp: componentBuilder.getChemCompTable(),
|
||||
atom_site
|
||||
});
|
||||
|
||||
return await createModels(basics, MolFormat.create(cube), ctx);
|
||||
return await createModels(basic, MolFormat.create(cube), ctx);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -27,6 +27,7 @@ function getBasic(atoms: GroAtoms, modelNum: number): BasicData {
|
||||
const asymIds = new Array<string>(atoms.count);
|
||||
const seqIds = new Uint32Array(atoms.count);
|
||||
const ids = new Uint32Array(atoms.count);
|
||||
const typeSymbol = new Array<string>(atoms.count);
|
||||
|
||||
const entityBuilder = new EntityBuilder();
|
||||
const componentBuilder = new ComponentBuilder(atoms.residueNumber, atoms.atomName);
|
||||
@@ -66,6 +67,8 @@ function getBasic(atoms: GroAtoms, modelNum: number): BasicData {
|
||||
asymIds[i] = currentAsymId;
|
||||
seqIds[i] = currentSeqId;
|
||||
ids[i] = i;
|
||||
|
||||
typeSymbol[i] = guessElementSymbolString(atoms.atomName.value(i), atoms.residueName.value(i));
|
||||
}
|
||||
|
||||
const auth_asym_id = Column.ofStringArray(asymIds);
|
||||
@@ -87,7 +90,7 @@ function getBasic(atoms: GroAtoms, modelNum: number): BasicData {
|
||||
label_entity_id: Column.ofStringArray(entityIds),
|
||||
|
||||
occupancy: Column.ofConst(1, atoms.count, Column.Schema.float),
|
||||
type_symbol: Column.ofStringArray(Column.mapToArray(atoms.atomName, s => guessElementSymbolString(s))),
|
||||
type_symbol: Column.ofStringArray(typeSymbol),
|
||||
|
||||
pdbx_PDB_model_num: Column.ofConst(modelNum, atoms.count, Column.Schema.int),
|
||||
}, atoms.count);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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>
|
||||
@@ -19,6 +19,7 @@ import { ComponentBond } from './property/bonds/chem_comp';
|
||||
import { StructConn } from './property/bonds/struct_conn';
|
||||
import { Trajectory } from '../../mol-model/structure';
|
||||
import { GlobalModelTransformInfo } from '../../mol-model/structure/model/properties/global-transform';
|
||||
import { createBasic } from './basic/schema';
|
||||
|
||||
function modelSymmetryFromMmcif(model: Model) {
|
||||
if (!MmcifFormat.is(model.sourceData)) return;
|
||||
@@ -100,5 +101,6 @@ namespace MmcifFormat {
|
||||
|
||||
export function trajectoryFromMmCIF(frame: CifFrame): Task<Trajectory> {
|
||||
const format = MmcifFormat.fromFrame(frame);
|
||||
return Task.create('Create mmCIF Model', ctx => createModels(format.data.db, format, ctx));
|
||||
const basic = createBasic(format.data.db, true);
|
||||
return Task.create('Create mmCIF Model', ctx => createModels(basic, format, ctx));
|
||||
}
|
||||
@@ -68,13 +68,13 @@ export async function getMolModels(mol: MolFile, format: ModelFormat<any> | unde
|
||||
componentBuilder.setNames([['MOL', 'Unknown Molecule']]);
|
||||
componentBuilder.add('MOL', 0);
|
||||
|
||||
const basics = createBasic({
|
||||
const basic = createBasic({
|
||||
entity: entityBuilder.getEntityTable(),
|
||||
chem_comp: componentBuilder.getChemCompTable(),
|
||||
atom_site
|
||||
});
|
||||
|
||||
const models = await createModels(basics, format ?? MolFormat.create(mol), ctx);
|
||||
const models = await createModels(basic, format ?? MolFormat.create(mol), ctx);
|
||||
|
||||
if (models.frameCount > 0) {
|
||||
const indexA = Column.ofIntArray(Column.mapToArray(bonds.atomIdxA, x => x - 1, Int32Array));
|
||||
|
||||
@@ -41,7 +41,7 @@ async function getModels(mol2: Mol2File, ctx: RuntimeContext) {
|
||||
for (let i = 0; i < atoms.count; ++i) {
|
||||
type_symbol[i] = hasAtomType
|
||||
? atoms.atom_type.value(i).split('.')[0].toUpperCase()
|
||||
: guessElementSymbolString(atoms.atom_name.value(i));
|
||||
: guessElementSymbolString(atoms.atom_name.value(i), atoms.subst_name.value(i));
|
||||
}
|
||||
|
||||
const atom_site = Table.ofPartialColumns(BasicSchema.atom_site, {
|
||||
@@ -75,13 +75,13 @@ async function getModels(mol2: Mol2File, ctx: RuntimeContext) {
|
||||
componentBuilder.add(atoms.subst_name.value(i), i);
|
||||
}
|
||||
|
||||
const basics = createBasic({
|
||||
const basic = createBasic({
|
||||
entity: entityBuilder.getEntityTable(),
|
||||
chem_comp: componentBuilder.getChemCompTable(),
|
||||
atom_site
|
||||
});
|
||||
|
||||
const _models = await createModels(basics, Mol2Format.create(mol2), ctx);
|
||||
const _models = await createModels(basic, Mol2Format.create(mol2), ctx);
|
||||
|
||||
if (_models.frameCount > 0) {
|
||||
const indexA = Column.ofIntArray(Column.mapToArray(bonds.origin_atom_id, x => x - 1, Int32Array));
|
||||
|
||||
52
src/mol-model-formats/structure/nctraj.ts
Normal file
52
src/mol-model-formats/structure/nctraj.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Task } from '../../mol-task';
|
||||
import { NctrajFile } from '../../mol-io/reader/nctraj/parser';
|
||||
import { Coordinates, Frame, Time } from '../../mol-model/structure/coordinates';
|
||||
import { Cell } from '../../mol-math/geometry/spacegroup/cell';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { Mutable } from '../../mol-util/type-helpers';
|
||||
|
||||
export function coordinatesFromNctraj(file: NctrajFile): Task<Coordinates> {
|
||||
return Task.create('Parse NCTRAJ', async ctx => {
|
||||
await ctx.update('Converting to coordinates');
|
||||
|
||||
const deltaTime = Time(file.deltaTime, 'step');
|
||||
const offsetTime = Time(file.timeOffset, deltaTime.unit);
|
||||
|
||||
const frames: Frame[] = [];
|
||||
for (let i = 0, il = file.coordinates.length; i < il; ++i) {
|
||||
const c = file.coordinates[i];
|
||||
const elementCount = c.length / 3;
|
||||
const x = new Float32Array(elementCount);
|
||||
const y = new Float32Array(elementCount);
|
||||
const z = new Float32Array(elementCount);
|
||||
for (let j = 0, jl = c.length; j < jl; j += 3) {
|
||||
x[j / 3] = c[j];
|
||||
y[j / 3] = c[j + 1];
|
||||
z[j / 3] = c[j + 2];
|
||||
}
|
||||
const frame: Mutable<Frame> = {
|
||||
elementCount,
|
||||
x, y, z,
|
||||
xyzOrdering: { isIdentity: true },
|
||||
time: Time(offsetTime.value + deltaTime.value * i, deltaTime.unit)
|
||||
};
|
||||
// TODO: handle case where cell_lengths and cell_angles are set, i.e., angles not 90deg
|
||||
if (file.cell_lengths) {
|
||||
const lengths = file.cell_lengths[i];
|
||||
const x = Vec3.scale(Vec3(), Vec3.unitX, lengths[0]);
|
||||
const y = Vec3.scale(Vec3(), Vec3.unitY, lengths[1]);
|
||||
const z = Vec3.scale(Vec3(), Vec3.unitZ, lengths[2]);
|
||||
frame.cell = Cell.fromBasis(x, y, z);
|
||||
}
|
||||
frames.push(frame);
|
||||
}
|
||||
|
||||
return Coordinates.create(frames, deltaTime, offsetTime);
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 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>
|
||||
@@ -14,6 +14,7 @@ import { Column } from '../../mol-data/db';
|
||||
import { AtomPartialCharge } from './property/partial-charge';
|
||||
import { Trajectory } from '../../mol-model/structure';
|
||||
import { ModelFormat } from '../format';
|
||||
import { createBasic } from './basic/schema';
|
||||
|
||||
export { PdbFormat };
|
||||
|
||||
@@ -34,7 +35,8 @@ export function trajectoryFromPDB(pdb: PdbFile): Task<Trajectory> {
|
||||
await ctx.update('Converting to mmCIF');
|
||||
const cif = await pdbToMmCif(pdb);
|
||||
const format = MmcifFormat.fromFrame(cif, undefined, PdbFormat.create(pdb));
|
||||
const models = await createModels(format.data.db, format, ctx);
|
||||
const basic = createBasic(format.data.db, true);
|
||||
const models = await createModels(basic, format, ctx);
|
||||
const partial_charge = cif.categories['atom_site']?.getField('partial_charge');
|
||||
if (partial_charge) {
|
||||
// TODO works only for single, unsorted model, to work generally
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 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>
|
||||
@@ -39,27 +39,99 @@ export function getAtomSiteTemplate(data: string, count: number) {
|
||||
};
|
||||
}
|
||||
|
||||
export function getAtomSite(sites: AtomSiteTemplate): { [K in keyof mmCIF_Schema['atom_site'] | 'partial_charge']?: CifField } {
|
||||
export function getAtomSite(sites: AtomSiteTemplate, hasTer: boolean): { [K in keyof mmCIF_Schema['atom_site'] | 'partial_charge']?: CifField } {
|
||||
const pdbx_PDB_model_num = CifField.ofStrings(sites.pdbx_PDB_model_num);
|
||||
const auth_asym_id = CifField.ofTokens(sites.auth_asym_id);
|
||||
const auth_seq_id = CifField.ofTokens(sites.auth_seq_id);
|
||||
const auth_atom_id = CifField.ofTokens(sites.auth_atom_id);
|
||||
const auth_comp_id = CifField.ofTokens(sites.auth_comp_id);
|
||||
const id = CifField.ofStrings(sites.id);
|
||||
|
||||
//
|
||||
|
||||
let currModelNum = pdbx_PDB_model_num.str(0);
|
||||
let currAsymId = auth_asym_id.str(0);
|
||||
let currSeqId = auth_seq_id.int(0);
|
||||
let currLabelAsymId = currAsymId;
|
||||
|
||||
const asymIdCounts = new Map<string, number>();
|
||||
const atomIdCounts = new Map<string, number>();
|
||||
|
||||
const labelAsymIds: string[] = [];
|
||||
const labelAtomIds: string[] = [];
|
||||
|
||||
// ensure unique asym ids per model and unique atom ids per seq id
|
||||
for (let i = 0, il = id.rowCount; i < il; ++i) {
|
||||
const modelNum = pdbx_PDB_model_num.str(i);
|
||||
const asymId = auth_asym_id.str(i);
|
||||
const seqId = auth_seq_id.int(i);
|
||||
let atomId = auth_atom_id.str(i);
|
||||
|
||||
let asymIdChanged = false;
|
||||
|
||||
if (modelNum !== currModelNum) {
|
||||
asymIdCounts.clear();
|
||||
atomIdCounts.clear();
|
||||
currModelNum = modelNum;
|
||||
currAsymId = asymId;
|
||||
currSeqId = seqId;
|
||||
asymIdChanged = true;
|
||||
currLabelAsymId = asymId;
|
||||
} else if (currAsymId !== asymId) {
|
||||
atomIdCounts.clear();
|
||||
currAsymId = asymId;
|
||||
currSeqId = seqId;
|
||||
asymIdChanged = true;
|
||||
currLabelAsymId = asymId;
|
||||
} else if (currSeqId !== seqId) {
|
||||
atomIdCounts.clear();
|
||||
currSeqId = seqId;
|
||||
}
|
||||
|
||||
if (asymIdCounts.has(asymId)) {
|
||||
// only change the chains name if there are TER records
|
||||
// otherwise assume repeated chain name use is from interleaved chains
|
||||
if (hasTer && asymIdChanged) {
|
||||
const asymIdCount = asymIdCounts.get(asymId)! + 1;
|
||||
asymIdCounts.set(asymId, asymIdCount);
|
||||
currLabelAsymId = `${asymId}_${asymIdCount}`;
|
||||
}
|
||||
} else {
|
||||
asymIdCounts.set(asymId, 0);
|
||||
}
|
||||
labelAsymIds[i] = currLabelAsymId;
|
||||
|
||||
if (atomIdCounts.has(atomId)) {
|
||||
const atomIdCount = atomIdCounts.get(atomId)! + 1;
|
||||
atomIdCounts.set(atomId, atomIdCount);
|
||||
atomId = `${atomId}_${atomIdCount}`;
|
||||
} else {
|
||||
atomIdCounts.set(atomId, 0);
|
||||
}
|
||||
labelAtomIds[i] = atomId;
|
||||
}
|
||||
|
||||
const labelAsymId = Column.ofStringArray(labelAsymIds);
|
||||
const labelAtomId = Column.ofStringArray(labelAtomIds);
|
||||
|
||||
//
|
||||
|
||||
return {
|
||||
auth_asym_id,
|
||||
auth_atom_id,
|
||||
auth_comp_id,
|
||||
auth_seq_id: CifField.ofTokens(sites.auth_seq_id),
|
||||
auth_seq_id,
|
||||
B_iso_or_equiv: CifField.ofTokens(sites.B_iso_or_equiv),
|
||||
Cartn_x: CifField.ofTokens(sites.Cartn_x),
|
||||
Cartn_y: CifField.ofTokens(sites.Cartn_y),
|
||||
Cartn_z: CifField.ofTokens(sites.Cartn_z),
|
||||
group_PDB: CifField.ofTokens(sites.group_PDB),
|
||||
id: CifField.ofStrings(sites.id),
|
||||
id,
|
||||
|
||||
label_alt_id: CifField.ofTokens(sites.label_alt_id),
|
||||
|
||||
label_asym_id: auth_asym_id,
|
||||
label_atom_id: auth_atom_id,
|
||||
label_asym_id: CifField.ofColumn(labelAsymId),
|
||||
label_atom_id: CifField.ofColumn(labelAtomId),
|
||||
label_comp_id: auth_comp_id,
|
||||
label_seq_id: CifField.ofUndefined(sites.index, Column.Schema.int),
|
||||
label_entity_id: CifField.ofStrings(sites.label_entity_id),
|
||||
@@ -68,7 +140,7 @@ export function getAtomSite(sites: AtomSiteTemplate): { [K in keyof mmCIF_Schema
|
||||
type_symbol: CifField.ofTokens(sites.type_symbol),
|
||||
|
||||
pdbx_PDB_ins_code: CifField.ofTokens(sites.pdbx_PDB_ins_code),
|
||||
pdbx_PDB_model_num: CifField.ofStrings(sites.pdbx_PDB_model_num),
|
||||
pdbx_PDB_model_num,
|
||||
|
||||
partial_charge: CifField.ofTokens(sites.partial_charge)
|
||||
};
|
||||
|
||||
@@ -23,19 +23,19 @@ const HelixTypes: {[k: string]: mmCIF_Schema['struct_conf']['conf_type_id']['T']
|
||||
// Left-handed gamma 8
|
||||
// 2 - 7 ribbon/helix 9
|
||||
// Polyproline 10
|
||||
1: 'HELX_RH_AL_P',
|
||||
2: 'HELX_RH_OM_P',
|
||||
3: 'HELX_RH_PI_P',
|
||||
4: 'HELX_RH_GA_P',
|
||||
5: 'HELX_RH_3T_P',
|
||||
6: 'HELX_LH_AL_P',
|
||||
7: 'HELX_LH_OM_P',
|
||||
8: 'HELX_LH_GA_P',
|
||||
9: 'HELX_RH_27_P', // TODO or left-handed???
|
||||
10: 'HELX_RH_PP_P', // TODO or left-handed???
|
||||
1: 'helx_rh_al_p',
|
||||
2: 'helx_rh_om_p',
|
||||
3: 'helx_rh_pi_p',
|
||||
4: 'helx_rh_ga_p',
|
||||
5: 'helx_rh_3t_p',
|
||||
6: 'helx_lh_al_p',
|
||||
7: 'helx_lh_om_p',
|
||||
8: 'helx_lh_ga_p',
|
||||
9: 'helx_rh_27_p', // TODO or left-handed???
|
||||
10: 'helx_rh_pp_p', // TODO or left-handed???
|
||||
};
|
||||
function getStructConfTypeId(type: string): mmCIF_Schema['struct_conf']['conf_type_id']['T'] {
|
||||
return HelixTypes[type] || 'HELX_P';
|
||||
return HelixTypes[type] || 'helx_p';
|
||||
}
|
||||
|
||||
interface PdbHelix {
|
||||
|
||||
@@ -51,6 +51,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> {
|
||||
|
||||
let modelNum = 0, modelStr = '';
|
||||
let conectRange: [number, number] | undefined = undefined;
|
||||
let hasTer = false;
|
||||
|
||||
for (let i = 0, _i = lines.count; i < _i; i++) {
|
||||
let s = indices[2 * i], e = indices[2 * i + 1];
|
||||
@@ -161,6 +162,10 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> {
|
||||
}
|
||||
// TODO: SCALE record => cif.atom_sites.fract_transf_matrix, cif.atom_sites.fract_transf_vector
|
||||
break;
|
||||
case 'T':
|
||||
if (substringStartsWith(data, s, e, 'TER')) {
|
||||
hasTer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +183,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> {
|
||||
atomSite.label_entity_id[i] = entityBuilder.getEntityId(compId, moleculeType, asymIds.value(i));
|
||||
}
|
||||
|
||||
const atom_site = getAtomSite(atomSite);
|
||||
const atom_site = getAtomSite(atomSite, hasTer);
|
||||
if (!isPdbqt) delete atom_site.partial_charge;
|
||||
|
||||
if (conectRange) {
|
||||
|
||||
174
src/mol-model-formats/structure/prmtop.ts
Normal file
174
src/mol-model-formats/structure/prmtop.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Column, Table } from '../../mol-data/db';
|
||||
import { PrmtopFile } from '../../mol-io/reader/prmtop/parser';
|
||||
import { getMoleculeType, MoleculeType } from '../../mol-model/structure/model/types';
|
||||
import { Topology } from '../../mol-model/structure/topology/topology';
|
||||
import { Task } from '../../mol-task';
|
||||
import { ModelFormat } from '../format';
|
||||
import { BasicSchema, createBasic } from './basic/schema';
|
||||
import { ComponentBuilder } from './common/component';
|
||||
import { EntityBuilder } from './common/entity';
|
||||
import { getChainId } from './common/util';
|
||||
import { guessElementSymbolString } from './util';
|
||||
|
||||
function getBasic(prmtop: PrmtopFile) {
|
||||
const { pointers, residuePointer, residueLabel, atomName } = prmtop;
|
||||
const atomCount = pointers.NATOM;
|
||||
const residueCount = pointers.NRES;
|
||||
|
||||
//
|
||||
|
||||
const residueIds = new Uint32Array(atomCount);
|
||||
const residueNames: string[] = [];
|
||||
|
||||
const addResidue = (i: number, from: number, to: number) => {
|
||||
const rn = residueLabel.value(i);
|
||||
for (let j = from, jl = to; j < jl; ++j) {
|
||||
residueIds[j] = i + 1;
|
||||
residueNames[j] = rn;
|
||||
}
|
||||
};
|
||||
|
||||
for (let i = 0, il = residueCount - 1; i < il; ++i) {
|
||||
addResidue(i, residuePointer.value(i) - 1, residuePointer.value(i + 1) - 1);
|
||||
|
||||
}
|
||||
addResidue(residueCount - 1, residuePointer.value(residueCount - 1) - 1, atomCount);
|
||||
|
||||
const residueId = Column.ofIntArray(residueIds);
|
||||
const residueName = Column.ofStringArray(residueNames);
|
||||
|
||||
//
|
||||
|
||||
const entityIds = new Array<string>(atomCount);
|
||||
const asymIds = new Array<string>(atomCount);
|
||||
const seqIds = new Uint32Array(atomCount);
|
||||
const ids = new Uint32Array(atomCount);
|
||||
|
||||
const entityBuilder = new EntityBuilder();
|
||||
const componentBuilder = new ComponentBuilder(residueId, atomName);
|
||||
|
||||
let currentEntityId = '';
|
||||
let currentAsymIndex = 0;
|
||||
let currentAsymId = '';
|
||||
let currentSeqId = 0;
|
||||
let prevMoleculeType = MoleculeType.Unknown;
|
||||
let prevResidueNumber = -1;
|
||||
|
||||
for (let i = 0, il = atomCount; i < il; ++i) {
|
||||
const residueNumber = residueId.value(i);
|
||||
if (residueNumber !== prevResidueNumber) {
|
||||
const compId = residueName.value(i);
|
||||
const moleculeType = getMoleculeType(componentBuilder.add(compId, i).type, compId);
|
||||
|
||||
if (moleculeType !== prevMoleculeType) {
|
||||
currentAsymId = getChainId(currentAsymIndex);
|
||||
currentAsymIndex += 1;
|
||||
currentSeqId = 0;
|
||||
}
|
||||
|
||||
currentEntityId = entityBuilder.getEntityId(compId, moleculeType, currentAsymId);
|
||||
currentSeqId += 1;
|
||||
|
||||
prevResidueNumber = residueNumber;
|
||||
prevMoleculeType = moleculeType;
|
||||
}
|
||||
|
||||
entityIds[i] = currentEntityId;
|
||||
asymIds[i] = currentAsymId;
|
||||
seqIds[i] = currentSeqId;
|
||||
ids[i] = i;
|
||||
}
|
||||
|
||||
const id = Column.ofIntArray(ids);
|
||||
const asym_id = Column.ofStringArray(asymIds);
|
||||
|
||||
//
|
||||
|
||||
const type_symbol = new Array<string>(atomCount);
|
||||
for (let i = 0; i < atomCount; ++i) {
|
||||
type_symbol[i] = guessElementSymbolString(atomName.value(i), residueName.value(i));
|
||||
}
|
||||
|
||||
const atom_site = Table.ofPartialColumns(BasicSchema.atom_site, {
|
||||
auth_asym_id: asym_id,
|
||||
auth_atom_id: Column.asArrayColumn(atomName),
|
||||
auth_comp_id: residueName,
|
||||
auth_seq_id: residueId,
|
||||
id: Column.asArrayColumn(id),
|
||||
|
||||
label_asym_id: asym_id,
|
||||
label_atom_id: Column.asArrayColumn(atomName),
|
||||
label_comp_id: residueName,
|
||||
label_seq_id: Column.ofIntArray(seqIds),
|
||||
label_entity_id: Column.ofStringArray(entityIds),
|
||||
|
||||
occupancy: Column.ofConst(1, atomCount, Column.Schema.float),
|
||||
type_symbol: Column.ofStringArray(type_symbol),
|
||||
|
||||
pdbx_PDB_model_num: Column.ofConst(1, atomCount, Column.Schema.int),
|
||||
}, atomCount);
|
||||
|
||||
const basic = createBasic({
|
||||
entity: entityBuilder.getEntityTable(),
|
||||
chem_comp: componentBuilder.getChemCompTable(),
|
||||
atom_site
|
||||
});
|
||||
|
||||
return basic;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
export { PrmtopFormat };
|
||||
|
||||
type PrmtopFormat = ModelFormat<PrmtopFile>
|
||||
|
||||
namespace PrmtopFormat {
|
||||
export function is(x?: ModelFormat): x is PrmtopFormat {
|
||||
return x?.kind === 'prmtop';
|
||||
}
|
||||
|
||||
export function fromPrmtop(prmtop: PrmtopFile): PrmtopFormat {
|
||||
return { kind: 'prmtop', name: prmtop.title.join(' ') || 'PRMTOP', data: prmtop };
|
||||
}
|
||||
}
|
||||
|
||||
export function topologyFromPrmtop(prmtop: PrmtopFile): Task<Topology> {
|
||||
return Task.create('Parse PRMTOP', async ctx => {
|
||||
const format = PrmtopFormat.fromPrmtop(prmtop);
|
||||
const basic = getBasic(prmtop);
|
||||
|
||||
const { pointers: { NBONH, NBONA }, bondsIncHydrogen, bondsWithoutHydrogen } = prmtop;
|
||||
const bondCount = NBONH + NBONA;
|
||||
|
||||
const bonds = {
|
||||
indexA: Column.ofLambda({
|
||||
value: (row: number) => {
|
||||
return row < NBONH
|
||||
? bondsIncHydrogen.value(row * 3) / 3
|
||||
: bondsWithoutHydrogen.value((row - NBONH) * 3) / 3;
|
||||
},
|
||||
rowCount: bondCount,
|
||||
schema: Column.Schema.int,
|
||||
}),
|
||||
indexB: Column.ofLambda({
|
||||
value: (row: number) => {
|
||||
return row < NBONH
|
||||
? bondsIncHydrogen.value(row * 3 + 1) / 3
|
||||
: bondsWithoutHydrogen.value((row - NBONH) * 3 + 1) / 3;
|
||||
},
|
||||
rowCount: bondCount,
|
||||
schema: Column.Schema.int,
|
||||
}),
|
||||
order: Column.ofConst(1, bondCount, Column.Schema.int)
|
||||
};
|
||||
|
||||
return Topology.create(prmtop.title.join(' ') || 'PRMTOP', basic, bonds, format);
|
||||
});
|
||||
}
|
||||
@@ -73,7 +73,7 @@ export namespace ComponentBond {
|
||||
const nameA = atom_id_1.value(i)!;
|
||||
const nameB = atom_id_2.value(i)!;
|
||||
const order = value_order.value(i)!;
|
||||
const aromatic = pdbx_aromatic_flag.value(i) === 'Y';
|
||||
const aromatic = pdbx_aromatic_flag.value(i) === 'y';
|
||||
|
||||
if (entry.id !== id) {
|
||||
entry = addEntry(id);
|
||||
|
||||
@@ -138,7 +138,7 @@ export namespace StructConn {
|
||||
if (partnerA === undefined || partnerB === undefined) continue;
|
||||
|
||||
const type = conn_type_id.value(i);
|
||||
const orderType = (pdbx_value_order.value(i) || '').toLowerCase();
|
||||
const orderType = (pdbx_value_order.value(i) || '');
|
||||
let flags = BondType.Flag.None;
|
||||
let order = 1;
|
||||
|
||||
|
||||
@@ -63,10 +63,21 @@ function getSpacegroupNameOrNumber(symmetry: Table<mmCIF_Schema['symmetry']>) {
|
||||
|
||||
function getSpacegroup(symmetry: Table<mmCIF_Schema['symmetry']>, cell: Table<mmCIF_Schema['cell']>): Spacegroup {
|
||||
if (symmetry._rowCount === 0 || cell._rowCount === 0) return Spacegroup.ZeroP1;
|
||||
|
||||
const a = cell.length_a.value(0);
|
||||
const b = cell.length_b.value(0);
|
||||
const c = cell.length_c.value(0);
|
||||
if (a === 0 || b === 0 || c === 0) return Spacegroup.ZeroP1;
|
||||
|
||||
const alpha = cell.angle_alpha.value(0);
|
||||
const beta = cell.angle_beta.value(0);
|
||||
const gamma = cell.angle_gamma.value(0);
|
||||
if (alpha === 0 || beta === 0 || gamma === 0) return Spacegroup.ZeroP1;
|
||||
|
||||
const nameOrNumber = getSpacegroupNameOrNumber(symmetry);
|
||||
const spaceCell = SpacegroupCell.create(nameOrNumber,
|
||||
Vec3.create(cell.length_a.value(0), cell.length_b.value(0), cell.length_c.value(0)),
|
||||
Vec3.scale(Vec3.zero(), Vec3.create(cell.angle_alpha.value(0), cell.angle_beta.value(0), cell.angle_gamma.value(0)), Math.PI / 180));
|
||||
Vec3.create(a, b, c),
|
||||
Vec3.scale(Vec3(), Vec3.create(alpha, beta, gamma), Math.PI / 180));
|
||||
|
||||
return Spacegroup.create(spaceCell);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ function getBasic(atoms: PsfFile['atoms']) {
|
||||
const asymIds = new Array<string>(atoms.count);
|
||||
const seqIds = new Uint32Array(atoms.count);
|
||||
const ids = new Uint32Array(atoms.count);
|
||||
const typeSymbol = new Array<string>(atoms.count);
|
||||
|
||||
const entityBuilder = new EntityBuilder();
|
||||
const componentBuilder = new ComponentBuilder(atoms.residueId, atoms.atomName);
|
||||
@@ -68,6 +69,8 @@ function getBasic(atoms: PsfFile['atoms']) {
|
||||
asymIds[i] = currentAsymId;
|
||||
seqIds[i] = currentSeqId;
|
||||
ids[i] = i;
|
||||
|
||||
typeSymbol[i] = guessElementSymbolString(atoms.atomName.value(i), atoms.residueName.value(i));
|
||||
}
|
||||
|
||||
const atom_site = Table.ofPartialColumns(BasicSchema.atom_site, {
|
||||
@@ -84,7 +87,7 @@ function getBasic(atoms: PsfFile['atoms']) {
|
||||
label_entity_id: Column.ofStringArray(entityIds),
|
||||
|
||||
occupancy: Column.ofConst(1, atoms.count, Column.Schema.float),
|
||||
type_symbol: Column.ofStringArray(Column.mapToArray(atoms.atomName, s => guessElementSymbolString(s))),
|
||||
type_symbol: Column.ofStringArray(typeSymbol),
|
||||
|
||||
pdbx_PDB_model_num: Column.ofConst(1, atoms.count, Column.Schema.int),
|
||||
}, atoms.count);
|
||||
|
||||
226
src/mol-model-formats/structure/top.ts
Normal file
226
src/mol-model-formats/structure/top.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Column, Table } from '../../mol-data/db';
|
||||
import { TopFile } from '../../mol-io/reader/top/parser';
|
||||
import { getMoleculeType, MoleculeType } from '../../mol-model/structure/model/types';
|
||||
import { Topology } from '../../mol-model/structure/topology/topology';
|
||||
import { Task } from '../../mol-task';
|
||||
import { ModelFormat } from '../format';
|
||||
import { BasicSchema, createBasic } from './basic/schema';
|
||||
import { ComponentBuilder } from './common/component';
|
||||
import { EntityBuilder } from './common/entity';
|
||||
import { getChainId } from './common/util';
|
||||
import { guessElementSymbolString } from './util';
|
||||
|
||||
function getBasic(top: TopFile) {
|
||||
const { molecules, compounds } = top;
|
||||
|
||||
const singleResidue: Record<string, boolean> = {};
|
||||
let atomCount = 0;
|
||||
|
||||
for (let i = 0, il = molecules._rowCount; i < il; ++i) {
|
||||
const mol = molecules.compound.value(i);
|
||||
const count = molecules.molCount.value(i);
|
||||
const { atoms } = compounds[mol];
|
||||
|
||||
Column.asArrayColumn(atoms.atom);
|
||||
Column.asArrayColumn(atoms.resnr);
|
||||
Column.asArrayColumn(atoms.residu);
|
||||
|
||||
atomCount += count * atoms._rowCount;
|
||||
|
||||
let prevResnr = atoms.resnr.value(0);
|
||||
singleResidue[mol] = true;
|
||||
for (let j = 1, jl = atoms._rowCount; j < jl; ++j) {
|
||||
const resnr = atoms.resnr.value(j);
|
||||
if (resnr !== prevResnr) {
|
||||
singleResidue[mol] = false;
|
||||
break;
|
||||
}
|
||||
prevResnr = resnr;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const atomNames = new Array<string>(atomCount);
|
||||
const residueIds = new Uint32Array(atomCount);
|
||||
const residueNames = new Array<string>(atomCount);
|
||||
|
||||
let k = 0;
|
||||
for (let i = 0, il = molecules._rowCount; i < il; ++i) {
|
||||
const mol = molecules.compound.value(i);
|
||||
const count = molecules.molCount.value(i);
|
||||
const { atoms } = compounds[mol];
|
||||
const isSingleResidue = singleResidue[mol];
|
||||
for (let j = 0; j < count; ++j) {
|
||||
for (let l = 0, ll = atoms._rowCount; l < ll; ++l) {
|
||||
atomNames[k] = atoms.atom.value(l);
|
||||
residueIds[k] = atoms.resnr.value(l);
|
||||
residueNames[k] = atoms.residu.value(l);
|
||||
|
||||
if (isSingleResidue) residueIds[k] += j;
|
||||
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const atomName = Column.ofStringArray(atomNames);
|
||||
const residueId = Column.ofIntArray(residueIds);
|
||||
const residueName = Column.ofStringArray(residueNames);
|
||||
|
||||
//
|
||||
|
||||
const entityIds = new Array<string>(atomCount);
|
||||
const asymIds = new Array<string>(atomCount);
|
||||
const seqIds = new Uint32Array(atomCount);
|
||||
const ids = new Uint32Array(atomCount);
|
||||
|
||||
const entityBuilder = new EntityBuilder();
|
||||
const componentBuilder = new ComponentBuilder(residueId, atomName);
|
||||
|
||||
let currentEntityId = '';
|
||||
let currentAsymIndex = 0;
|
||||
let currentAsymId = '';
|
||||
let currentSeqId = 0;
|
||||
let prevMoleculeType = MoleculeType.Unknown;
|
||||
let prevResidueNumber = -1;
|
||||
|
||||
for (let i = 0, il = atomCount; i < il; ++i) {
|
||||
const residueNumber = residueId.value(i);
|
||||
if (residueNumber !== prevResidueNumber) {
|
||||
const compId = residueName.value(i);
|
||||
const moleculeType = getMoleculeType(componentBuilder.add(compId, i).type, compId);
|
||||
|
||||
if (moleculeType !== prevMoleculeType) {
|
||||
currentAsymId = getChainId(currentAsymIndex);
|
||||
currentAsymIndex += 1;
|
||||
currentSeqId = 0;
|
||||
}
|
||||
|
||||
currentEntityId = entityBuilder.getEntityId(compId, moleculeType, currentAsymId);
|
||||
currentSeqId += 1;
|
||||
|
||||
prevResidueNumber = residueNumber;
|
||||
prevMoleculeType = moleculeType;
|
||||
}
|
||||
|
||||
entityIds[i] = currentEntityId;
|
||||
asymIds[i] = currentAsymId;
|
||||
seqIds[i] = currentSeqId;
|
||||
ids[i] = i;
|
||||
}
|
||||
|
||||
const id = Column.ofIntArray(ids);
|
||||
const asym_id = Column.ofStringArray(asymIds);
|
||||
|
||||
//
|
||||
|
||||
const type_symbol = new Array<string>(atomCount);
|
||||
for (let i = 0; i < atomCount; ++i) {
|
||||
type_symbol[i] = guessElementSymbolString(atomName.value(i), residueName.value(i));
|
||||
}
|
||||
|
||||
const atom_site = Table.ofPartialColumns(BasicSchema.atom_site, {
|
||||
auth_asym_id: asym_id,
|
||||
auth_atom_id: Column.asArrayColumn(atomName),
|
||||
auth_comp_id: residueName,
|
||||
auth_seq_id: residueId,
|
||||
id: Column.asArrayColumn(id),
|
||||
|
||||
label_asym_id: asym_id,
|
||||
label_atom_id: Column.asArrayColumn(atomName),
|
||||
label_comp_id: residueName,
|
||||
label_seq_id: Column.ofIntArray(seqIds),
|
||||
label_entity_id: Column.ofStringArray(entityIds),
|
||||
|
||||
occupancy: Column.ofConst(1, atomCount, Column.Schema.float),
|
||||
type_symbol: Column.ofStringArray(type_symbol),
|
||||
|
||||
pdbx_PDB_model_num: Column.ofConst(1, atomCount, Column.Schema.int),
|
||||
}, atomCount);
|
||||
|
||||
const basic = createBasic({
|
||||
entity: entityBuilder.getEntityTable(),
|
||||
chem_comp: componentBuilder.getChemCompTable(),
|
||||
atom_site
|
||||
});
|
||||
|
||||
return basic;
|
||||
}
|
||||
|
||||
function getBonds(top: TopFile) {
|
||||
const { molecules, compounds } = top;
|
||||
|
||||
const indexA: number[] = [];
|
||||
const indexB: number[] = [];
|
||||
|
||||
let atomOffset = 0;
|
||||
|
||||
for (let i = 0, il = molecules._rowCount; i < il; ++i) {
|
||||
const mol = molecules.compound.value(i);
|
||||
const count = molecules.molCount.value(i);
|
||||
const { atoms, bonds } = compounds[mol];
|
||||
|
||||
|
||||
|
||||
if (bonds) {
|
||||
for (let j = 0; j < count; ++j) {
|
||||
|
||||
for (let l = 0, ll = bonds._rowCount; l < ll; ++l) {
|
||||
indexA.push(bonds.ai.value(l) - 1 + atomOffset);
|
||||
indexB.push(bonds.aj.value(l) - 1 + atomOffset);
|
||||
}
|
||||
|
||||
atomOffset += atoms._rowCount;
|
||||
}
|
||||
} else if (mol === 'TIP3') {
|
||||
for (let j = 0; j < count; ++j) {
|
||||
indexA.push(0 + atomOffset);
|
||||
indexB.push(1 + atomOffset);
|
||||
indexA.push(0 + atomOffset);
|
||||
indexB.push(2 + atomOffset);
|
||||
atomOffset += atoms._rowCount;
|
||||
}
|
||||
} else {
|
||||
atomOffset += count * atoms._rowCount;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
indexA: Column.ofIntArray(indexA),
|
||||
indexB: Column.ofIntArray(indexB),
|
||||
order: Column.ofConst(1, indexA.length, Column.Schema.int)
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
export { TopFormat };
|
||||
|
||||
type TopFormat = ModelFormat<TopFile>
|
||||
|
||||
namespace TopFormat {
|
||||
export function is(x?: ModelFormat): x is TopFormat {
|
||||
return x?.kind === 'top';
|
||||
}
|
||||
|
||||
export function fromTop(top: TopFile): TopFormat {
|
||||
return { kind: 'top', name: top.system || 'TOP', data: top };
|
||||
}
|
||||
}
|
||||
|
||||
export function topologyFromTop(top: TopFile): Task<Topology> {
|
||||
return Task.create('Parse TOP', async ctx => {
|
||||
const format = TopFormat.fromTop(top);
|
||||
const basic = getBasic(top);
|
||||
const bonds = getBonds(top);
|
||||
|
||||
return Topology.create(top.system || 'TOP', basic, bonds, format);
|
||||
});
|
||||
}
|
||||
39
src/mol-model-formats/structure/trr.ts
Normal file
39
src/mol-model-formats/structure/trr.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Task } from '../../mol-task';
|
||||
import { TrrFile } from '../../mol-io/reader/trr/parser';
|
||||
import { Coordinates, Frame, Time } from '../../mol-model/structure/coordinates';
|
||||
import { Cell } from '../../mol-math/geometry/spacegroup/cell';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra';
|
||||
|
||||
export function coordinatesFromTrr(file: TrrFile): Task<Coordinates> {
|
||||
return Task.create('Parse TRR', async ctx => {
|
||||
await ctx.update('Converting to coordinates');
|
||||
|
||||
const deltaTime = Time(file.deltaTime, 'step');
|
||||
const offsetTime = Time(file.timeOffset, deltaTime.unit);
|
||||
|
||||
const frames: Frame[] = [];
|
||||
for (let i = 0, il = file.frames.length; i < il; ++i) {
|
||||
const box = file.boxes[i];
|
||||
const x = Vec3.fromArray(Vec3(), box, 0);
|
||||
const y = Vec3.fromArray(Vec3(), box, 3);
|
||||
const z = Vec3.fromArray(Vec3(), box, 6);
|
||||
frames.push({
|
||||
elementCount: file.frames[i].count,
|
||||
cell: Cell.fromBasis(x, y, z),
|
||||
x: file.frames[i].x,
|
||||
y: file.frames[i].y,
|
||||
z: file.frames[i].z,
|
||||
xyzOrdering: { isIdentity: true },
|
||||
time: Time(offsetTime.value + deltaTime.value * i, deltaTime.unit)
|
||||
});
|
||||
}
|
||||
|
||||
return Coordinates.create(frames, deltaTime, offsetTime);
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -46,31 +46,30 @@ export function guessElementSymbolTokens(tokens: Tokens, str: string, start: num
|
||||
TokenBuilder.add(tokens, s, s); // no reasonable guess, add empty token
|
||||
}
|
||||
|
||||
const TwoCharElementNames = new Set(['NA', 'CL', 'FE', 'SI', 'BR', 'AS']);
|
||||
const OneCharElementNames = new Set(['C', 'H', 'N', 'O', 'P', 'S']);
|
||||
|
||||
const reTrimSpacesAndNumbers = /^[\s\d]+|[\s\d]+$/g;
|
||||
export function guessElementSymbolString(str: string) {
|
||||
export function guessElementSymbolString(atomId: string, compId: string) {
|
||||
// trim spaces and numbers, convert to upper case
|
||||
str = str.replace(reTrimSpacesAndNumbers, '').toUpperCase();
|
||||
const l = str.length;
|
||||
atomId = atomId.replace(reTrimSpacesAndNumbers, '').toUpperCase();
|
||||
const l = atomId.length;
|
||||
|
||||
if (l === 0) return str; // empty
|
||||
if (l === 1) return str; // one char
|
||||
if (l === 0) return atomId; // empty
|
||||
if (l === 1) return atomId; // one char
|
||||
if (TwoCharElementNames.has(atomId)) return atomId; // two chars
|
||||
|
||||
if (l === 2) { // two chars
|
||||
if (str === 'NA' || str === 'CL' || str === 'FE' || str === 'SI' ||
|
||||
str === 'BR' || str === 'AS'
|
||||
) return str;
|
||||
// check for Charmm ion names where component and atom id are the same
|
||||
if (l === 3 && compId === atomId) {
|
||||
if (atomId === 'SOD') return 'NA';
|
||||
if (atomId === 'POT') return 'K';
|
||||
if (atomId === 'CES') return 'CS';
|
||||
if (atomId === 'CAL') return 'CA';
|
||||
if (atomId === 'CLA') return 'CL';
|
||||
}
|
||||
|
||||
if (l === 3) { // three chars
|
||||
if (str === 'SOD') return 'NA';
|
||||
if (str === 'POT') return 'K';
|
||||
if (str === 'CES') return 'CS';
|
||||
if (str === 'CAL') return 'CA';
|
||||
if (str === 'CLA') return 'CL';
|
||||
}
|
||||
|
||||
const c = str[0];
|
||||
if (c === 'C' || c === 'H' || c === 'N' || c === 'O' || c === 'P' || c === 'S') return c;
|
||||
if (OneCharElementNames.has(atomId[0])) return atomId[0];
|
||||
|
||||
return ''; // no reasonable guess, return empty string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,13 +78,13 @@ function getModels(mol: XyzFile, ctx: RuntimeContext) {
|
||||
componentBuilder.setNames([['MOL', 'Unknown Molecule']]);
|
||||
componentBuilder.add('MOL', 0);
|
||||
|
||||
const basics = createBasic({
|
||||
const basic = createBasic({
|
||||
entity: entityBuilder.getEntityTable(),
|
||||
chem_comp: componentBuilder.getChemCompTable(),
|
||||
atom_site
|
||||
});
|
||||
|
||||
return createModels(basics, XyzFormat.create(mol), ctx);
|
||||
return createModels(basic, XyzFormat.create(mol), ctx);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import { AminoAlphabet, NuclecicAlphabet, getProteinOneLetterCode, getRnaOneLetterCode, getDnaOneLetterCode } from './constants';
|
||||
import { Column } from '../../mol-data/db';
|
||||
import { assertUnreachable } from '../../mol-util/type-helpers';
|
||||
|
||||
// TODO add mapping support to other sequence spaces, e.g. uniprot
|
||||
|
||||
@@ -66,7 +67,7 @@ namespace Sequence {
|
||||
case Kind.DNA: code = getDnaOneLetterCode; break;
|
||||
case Kind.RNA: code = getRnaOneLetterCode; break;
|
||||
case Kind.Generic: code = () => 'X'; break;
|
||||
default: throw new Error(`unknown kind '${kind}'`);
|
||||
default: assertUnreachable(kind);
|
||||
}
|
||||
if (map && map.size > 0) {
|
||||
return (name: string) => {
|
||||
|
||||
@@ -30,6 +30,7 @@ import { Trajectory, ArrayTrajectory } from '../trajectory';
|
||||
import { Unit } from '../structure';
|
||||
import { SortedArray } from '../../../mol-data/int/sorted-array';
|
||||
import { PolymerType } from './types';
|
||||
import { ModelSecondaryStructure } from '../../../mol-model-formats/structure/property/secondary-structure';
|
||||
|
||||
/**
|
||||
* Interface to the "source data" of the molecule.
|
||||
@@ -99,9 +100,14 @@ export namespace Model {
|
||||
const isIdentity = Column.isIdentity(srcIndex);
|
||||
const srcIndexArray = isIdentity ? void 0 : srcIndex.toArray({ array: Int32Array });
|
||||
const coarseGrained = isCoarseGrained(model);
|
||||
const elementCount = model.atomicHierarchy.atoms._rowCount;
|
||||
|
||||
for (let i = 0, il = frames.length; i < il; ++i) {
|
||||
const f = frames[i];
|
||||
if (f.elementCount !== elementCount) {
|
||||
throw new Error(`Frame element count mismatch, got ${f.elementCount} but expected ${elementCount}.`);
|
||||
}
|
||||
|
||||
const m = {
|
||||
...model,
|
||||
id: UUID.create22(),
|
||||
@@ -297,7 +303,7 @@ export namespace Model {
|
||||
if (!MmcifFormat.is(model.sourceData)) return false;
|
||||
const { db } = model.sourceData.data;
|
||||
for (let i = 0, il = db.database_2.database_id.rowCount; i < il; ++i) {
|
||||
if (db.database_2.database_id.value(i) === 'PDB') return true;
|
||||
if (db.database_2.database_id.value(i) === 'pdb') return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -313,12 +319,15 @@ export namespace Model {
|
||||
}
|
||||
|
||||
export function hasSecondaryStructure(model: Model): boolean {
|
||||
if (!MmcifFormat.is(model.sourceData)) return false;
|
||||
const { db } = model.sourceData.data;
|
||||
return (
|
||||
db.struct_conf.id.isDefined ||
|
||||
db.struct_sheet_range.id.isDefined
|
||||
);
|
||||
if (MmcifFormat.is(model.sourceData)) {
|
||||
const { db } = model.sourceData.data;
|
||||
return (
|
||||
db.struct_conf.id.isDefined ||
|
||||
db.struct_sheet_range.id.isDefined
|
||||
);
|
||||
} else {
|
||||
return ModelSecondaryStructure.Provider.isApplicable(model);
|
||||
}
|
||||
}
|
||||
|
||||
const tmpAngles90 = Vec3.create(1.5707963, 1.5707963, 1.5707963); // in radians
|
||||
|
||||
@@ -17,7 +17,7 @@ export type EntitySubtype = (
|
||||
'lipid' |
|
||||
'peptide-like'
|
||||
)
|
||||
export const EntitySubtype = Column.Schema.Aliased<EntitySubtype>(Column.Schema.Str(''));
|
||||
export const EntitySubtype = Column.Schema.Aliased<EntitySubtype>(Column.Schema.Str());
|
||||
|
||||
export interface Entities {
|
||||
data: mmCIF_Database['entity'],
|
||||
|
||||
@@ -11,6 +11,9 @@ import { MoleculeType, getMoleculeType, getComponentType, PolymerType, getPolyme
|
||||
import { getAtomIdForAtomRole } from '../../../../../mol-model/structure/util';
|
||||
import { ChemicalComponentMap } from '../common';
|
||||
import { isProductionMode } from '../../../../../mol-util/debug';
|
||||
import { mmCIF_chemComp_schema } from '../../../../../mol-io/reader/cif/schema/mmcif-extras';
|
||||
|
||||
type ChemCompType = mmCIF_chemComp_schema['type']['T'];
|
||||
|
||||
export function getAtomicDerivedData(data: AtomicData, segments: AtomicSegments, index: AtomicIndex, chemicalComponentMap: ChemicalComponentMap): AtomicDerivedData {
|
||||
const { label_comp_id, type_symbol, _rowCount: atomCount } = data.atoms;
|
||||
@@ -42,7 +45,7 @@ export function getAtomicDerivedData(data: AtomicData, segments: AtomicSegments,
|
||||
molType = moleculeTypeMap.get(compId)!;
|
||||
polyType = polymerTypeMap.get(compId)!;
|
||||
} else {
|
||||
let type: string;
|
||||
let type: ChemCompType;
|
||||
if (chemCompMap.has(compId)) {
|
||||
type = chemCompMap.get(compId)!.type;
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
@@ -162,39 +162,41 @@ export const NucleicBackboneAtoms = new Set([
|
||||
'O2*', 'O3*', 'O4*', 'O5*', 'C1*', 'C2*', 'C3*', 'C4*', 'C5*'
|
||||
]);
|
||||
|
||||
type ChemCompType = mmCIF_chemComp_schema['type']['T'];
|
||||
|
||||
/** Chemical component type names for D-linked protein */
|
||||
export const DProteinComponentTypeNames = new Set([
|
||||
'D-PEPTIDE LINKING', 'D-PEPTIDE NH3 AMINO TERMINUS',
|
||||
'D-PEPTIDE COOH CARBOXY TERMINUS', 'D-GAMMA-PEPTIDE, C-DELTA LINKING',
|
||||
'D-BETA-PEPTIDE, C-GAMMA LINKING'
|
||||
export const DProteinComponentTypeNames = new Set<ChemCompType>([
|
||||
'd-peptide linking', 'd-peptide nh3 amino terminus',
|
||||
'd-peptide cooh carboxy terminus', 'd-gamma-peptide, c-delta linking',
|
||||
'd-beta-peptide, c-gamma linking'
|
||||
]);
|
||||
|
||||
/** Chemical component type names for L-linked protein */
|
||||
export const LProteinComponentTypeNames = new Set([
|
||||
'L-PEPTIDE LINKING', 'L-PEPTIDE NH3 AMINO TERMINUS',
|
||||
'L-PEPTIDE COOH CARBOXY TERMINUS', 'L-GAMMA-PEPTIDE, C-DELTA LINKING',
|
||||
'L-BETA-PEPTIDE, C-GAMMA LINKING'
|
||||
export const LProteinComponentTypeNames = new Set<ChemCompType>([
|
||||
'l-peptide linking', 'l-peptide nh3 amino terminus',
|
||||
'l-peptide cooh carboxy terminus', 'l-gamma-peptide, c-delta linking',
|
||||
'l-beta-peptide, c-gamma linking'
|
||||
]);
|
||||
|
||||
/** Chemical component type names for gamma protein, overlaps with D/L-linked */
|
||||
export const GammaProteinComponentTypeNames = new Set([
|
||||
'D-GAMMA-PEPTIDE, C-DELTA LINKING', 'L-GAMMA-PEPTIDE, C-DELTA LINKING'
|
||||
export const GammaProteinComponentTypeNames = new Set<ChemCompType>([
|
||||
'd-gamma-peptide, c-delta linking', 'l-gamma-peptide, c-delta linking'
|
||||
]);
|
||||
|
||||
/** Chemical component type names for beta protein, overlaps with D/L-linked */
|
||||
export const BetaProteinComponentTypeNames = new Set([
|
||||
'D-BETA-PEPTIDE, C-GAMMA LINKING', 'L-BETA-PEPTIDE, C-GAMMA LINKING'
|
||||
export const BetaProteinComponentTypeNames = new Set<ChemCompType>([
|
||||
'd-beta-peptide, c-gamma linking', 'l-beta-peptide, c-gamma linking'
|
||||
]);
|
||||
|
||||
/** Chemical component type names for protein termini, overlaps with D/L-linked */
|
||||
export const ProteinTerminusComponentTypeNames = new Set([
|
||||
'D-PEPTIDE NH3 AMINO TERMINUS', 'D-PEPTIDE COOH CARBOXY TERMINUS',
|
||||
'L-PEPTIDE NH3 AMINO TERMINUS', 'L-PEPTIDE COOH CARBOXY TERMINUS'
|
||||
export const ProteinTerminusComponentTypeNames = new Set<ChemCompType>([
|
||||
'd-peptide nh3 amino terminus', 'd-peptide cooh carboxy terminus',
|
||||
'l-peptide nh3 amino terminus', 'l-peptide cooh carboxy terminus'
|
||||
]);
|
||||
|
||||
/** Chemical component type names for peptide-like protein */
|
||||
export const OtherProteinComponentTypeNames = new Set([
|
||||
'PEPTIDE LINKING', 'PEPTIDE-LIKE',
|
||||
export const OtherProteinComponentTypeNames = new Set<ChemCompType>([
|
||||
'peptide linking', 'peptide-like',
|
||||
]);
|
||||
|
||||
/** Chemical component type names for protein */
|
||||
@@ -203,38 +205,42 @@ export const ProteinComponentTypeNames = SetUtils.unionMany(
|
||||
);
|
||||
|
||||
/** Chemical component type names for DNA */
|
||||
export const DNAComponentTypeNames = new Set([
|
||||
'DNA LINKING', 'L-DNA LINKING', 'DNA OH 5 PRIME TERMINUS', 'DNA OH 3 PRIME TERMINUS',
|
||||
export const DNAComponentTypeNames = new Set<ChemCompType>([
|
||||
'dna linking', 'l-dna linking', 'dna oh 5 prime terminus', 'dna oh 3 prime terminus',
|
||||
]);
|
||||
|
||||
/** Chemical component type names for RNA */
|
||||
export const RNAComponentTypeNames = new Set([
|
||||
'RNA LINKING', 'L-RNA LINKING', 'RNA OH 5 PRIME TERMINUS', 'RNA OH 3 PRIME TERMINUS',
|
||||
export const RNAComponentTypeNames = new Set<ChemCompType>([
|
||||
'rna linking', 'l-rna linking', 'rna oh 5 prime terminus', 'rna oh 3 prime terminus',
|
||||
]);
|
||||
|
||||
/** Chemical component type names for saccharide */
|
||||
export const SaccharideComponentTypeNames = new Set([
|
||||
'D-SACCHARIDE, BETA LINKING', 'L-SACCHARIDE, BETA LINKING',
|
||||
'D-SACCHARIDE, ALPHA LINKING', 'L-SACCHARIDE, ALPHA LINKING',
|
||||
'L-SACCHARIDE', 'D-SACCHARIDE', 'SACCHARIDE',
|
||||
// the following four are marked to be deprecated in the mmCIF dictionary
|
||||
'D-SACCHARIDE 1,4 AND 1,4 LINKING', 'L-SACCHARIDE 1,4 AND 1,4 LINKING',
|
||||
'D-SACCHARIDE 1,4 AND 1,6 LINKING', 'L-SACCHARIDE 1,4 AND 1,6 LINKING',
|
||||
]);
|
||||
export const SaccharideComponentTypeNames = SetUtils.unionMany(
|
||||
new Set<ChemCompType>([
|
||||
'd-saccharide, beta linking', 'l-saccharide, beta linking',
|
||||
'd-saccharide, alpha linking', 'l-saccharide, alpha linking',
|
||||
'l-saccharide', 'd-saccharide', 'saccharide',
|
||||
]),
|
||||
// deprecated in the mmCIF dictionary, kept for backward compatibility
|
||||
new Set([
|
||||
'd-saccharide 1,4 and 1,4 linking', 'l-saccharide 1,4 and 1,4 linking',
|
||||
'd-saccharide 1,4 and 1,6 linking', 'l-saccharide 1,4 and 1,6 linking'
|
||||
]),
|
||||
);
|
||||
|
||||
/** Chemical component type names for other */
|
||||
export const OtherComponentTypeNames = new Set([
|
||||
'NON-POLYMER', 'OTHER'
|
||||
export const OtherComponentTypeNames = new Set<ChemCompType>([
|
||||
'non-polymer', 'other'
|
||||
]);
|
||||
|
||||
/** Chemical component type names for ion (extension to mmcif) */
|
||||
export const IonComponentTypeNames = new Set([
|
||||
'ION'
|
||||
export const IonComponentTypeNames = new Set<ChemCompType>([
|
||||
'ion'
|
||||
]);
|
||||
|
||||
/** Chemical component type names for lipid (extension to mmcif) */
|
||||
export const LipidComponentTypeNames = new Set([
|
||||
'LIPID'
|
||||
export const LipidComponentTypeNames = new Set<ChemCompType>([
|
||||
'lipid'
|
||||
]);
|
||||
|
||||
/** Common names for water molecules */
|
||||
@@ -298,8 +304,7 @@ export const isPyrimidineBase = (compId: string) => PyrimidineBaseNames.has(comp
|
||||
export const PolymerNames = SetUtils.unionMany(AminoAcidNames, BaseNames);
|
||||
|
||||
/** get the molecule type from component type and id */
|
||||
export function getMoleculeType(compType: string, compId: string): MoleculeType {
|
||||
compType = compType.toUpperCase();
|
||||
export function getMoleculeType(compType: ChemCompType, compId: string): MoleculeType {
|
||||
compId = compId.toUpperCase();
|
||||
if (PeptideBaseNames.has(compId)) {
|
||||
return MoleculeType.PNA;
|
||||
@@ -319,7 +324,7 @@ export function getMoleculeType(compType: string, compId: string): MoleculeType
|
||||
return MoleculeType.Lipid;
|
||||
} else if (OtherComponentTypeNames.has(compType)) {
|
||||
if (SaccharideCompIdMap.has(compId)) {
|
||||
// trust our saccharide table more than given 'non-polymer' or 'other' component type
|
||||
// trust our saccharide table more than given 'NON-POLYMER' or 'OTHER' component type
|
||||
return MoleculeType.Saccharide;
|
||||
} else if (AminoAcidNames.has(compId)) {
|
||||
return MoleculeType.Protein;
|
||||
@@ -335,8 +340,7 @@ export function getMoleculeType(compType: string, compId: string): MoleculeType
|
||||
}
|
||||
}
|
||||
|
||||
export function getPolymerType(compType: string, molType: MoleculeType): PolymerType {
|
||||
compType = compType.toUpperCase();
|
||||
export function getPolymerType(compType: ChemCompType, molType: MoleculeType): PolymerType {
|
||||
if (molType === MoleculeType.Protein) {
|
||||
if (GammaProteinComponentTypeNames.has(compType)) {
|
||||
return PolymerType.GammaProtein;
|
||||
@@ -358,14 +362,14 @@ export function getPolymerType(compType: string, molType: MoleculeType): Polymer
|
||||
}
|
||||
}
|
||||
|
||||
export function getComponentType(compId: string): mmCIF_chemComp_schema['type']['T'] {
|
||||
export function getComponentType(compId: string): ChemCompType {
|
||||
compId = compId.toUpperCase();
|
||||
if (AminoAcidNames.has(compId)) {
|
||||
return 'peptide linking';
|
||||
} else if (RnaBaseNames.has(compId)) {
|
||||
return 'RNA linking';
|
||||
return 'rna linking';
|
||||
} else if (DnaBaseNames.has(compId)) {
|
||||
return 'DNA linking';
|
||||
return 'dna linking';
|
||||
} else if (SaccharideCompIdMap.has(compId)) {
|
||||
return 'saccharide';
|
||||
} else {
|
||||
@@ -400,9 +404,8 @@ export function getEntityType(compId: string): mmCIF_Schema['entity']['type']['T
|
||||
}
|
||||
}
|
||||
|
||||
export function getEntitySubtype(compId: string, compType: string): EntitySubtype {
|
||||
export function getEntitySubtype(compId: string, compType: ChemCompType): EntitySubtype {
|
||||
compId = compId.toUpperCase();
|
||||
compType = compType.toUpperCase();
|
||||
if (LProteinComponentTypeNames.has(compType)) {
|
||||
return 'polypeptide(L)';
|
||||
} else if (DProteinComponentTypeNames.has(compType)) {
|
||||
|
||||
9
src/mol-model/structure/model/types/saccharides.ts
Normal file
9
src/mol-model/structure/model/types/saccharides.ts
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user