diff --git a/data/mmcif-field-names.csv b/data/mmcif-field-names.csv index 45602d31ed609b3422c9bff19906fd5ffe8f1ce8..fba153c636ab478f0cdf50ec74a25b7e2245bfa5 100644 --- a/data/mmcif-field-names.csv +++ b/data/mmcif-field-names.csv @@ -123,6 +123,17 @@ pdbx_entity_descriptor.type pdbx_entity_descriptor.program pdbx_entity_descriptor.program_version +pdbx_nonpoly_scheme.asym_id +pdbx_nonpoly_scheme.entity_id +pdbx_nonpoly_scheme.mon_id +pdbx_nonpoly_scheme.ndb_seq_num +pdbx_nonpoly_scheme.pdb_seq_num +pdbx_nonpoly_scheme.auth_seq_num +pdbx_nonpoly_scheme.pdb_mon_id +pdbx_nonpoly_scheme.auth_mon_id +pdbx_nonpoly_scheme.pdb_strand_id +pdbx_nonpoly_scheme.pdb_ins_code + entry.id exptl.entry_id diff --git a/docs/model-server/readme.md b/docs/model-server/readme.md index b4b197c0f04baa2985bd9ded03805c7d00604a8f..02d151c86b4e00c6a6df74844e4b8e966be62325 100644 --- a/docs/model-server/readme.md +++ b/docs/model-server/readme.md @@ -14,6 +14,14 @@ npm install Customize configuration at ``src/server/model/config.ts`` to point to your data and which custom properties to include (see the [Custom Properties](#custom-properties) section). Alternatively, the config can be edited in the compiled version in ``build/node_modules/servers/model/config.js``. +Afterwards, build the project: + +``` +npm run build +``` + +(or run watch mode for automatic rebuilds: ``npm run watch``) + Running the server locally for testing: ``` npm run model-server diff --git a/src/mol-io/reader/cif/schema/mmcif.ts b/src/mol-io/reader/cif/schema/mmcif.ts index b0799e894d3049013f18076b7fe913df6b2df5fd..d2565a478cdb4bb7a9deebaacf3afec883279d59 100644 --- a/src/mol-io/reader/cif/schema/mmcif.ts +++ b/src/mol-io/reader/cif/schema/mmcif.ts @@ -1950,6 +1950,18 @@ export const mmCIF_Schema = { */ ordinal: int, }, + pdbx_nonpoly_scheme: { + asym_id: str, + entity_id: str, + mon_id: str, + ndb_seq_num: int, + pdb_seq_num: int, + auth_seq_num: int, + pdb_mon_id: str, + auth_mon_id: str, + pdb_strand_id: str, + pdb_ins_code: str + }, /** * Data items in the IHM_STARTING_MODEL_DETAILS category records the * details about structural models used as starting inputs in diff --git a/src/mol-math/geometry/gaussian-density.ts b/src/mol-math/geometry/gaussian-density.ts index b05bb1108e59eb340109b60c2ec2ec585b91fb80..16577af6b9305216a661bd28cf7e917a9913d20d 100644 --- a/src/mol-math/geometry/gaussian-density.ts +++ b/src/mol-math/geometry/gaussian-density.ts @@ -8,9 +8,13 @@ import { Box3D } from '../geometry'; import { Vec3 } from '../linear-algebra'; import { RuntimeContext, Task } from 'mol-task'; import { PositionData, DensityData } from './common'; -import { GaussianDensityGPU } from './gaussian-density/gpu'; import { GaussianDensityCPU } from './gaussian-density/cpu'; +// import { GaussianDensityGPU } from './gaussian-density/gpu'; +const GaussianDensityGPU = typeof document !== 'undefined' + ? (require('./gaussian-density/gpu') as typeof import('./gaussian-density/gpu')).GaussianDensityGPU + : void 0; + export const DefaultGaussianDensityProps = { resolution: 1, radiusOffset: 0, @@ -36,6 +40,7 @@ export function computeGaussianDensity(position: PositionData, box: Box3D, radiu export async function GaussianDensity(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> { if (props.useGpu) { + if (!GaussianDensityGPU) throw 'GPU computation not supported on this platform'; return await GaussianDensityGPU(ctx, position, box, radius, props) } else { return await GaussianDensityCPU(ctx, position, box, radius, props) diff --git a/src/mol-model/structure/export/categories/misc.ts b/src/mol-model/structure/export/categories/misc.ts index 39d3d40f2b1f0202235618e09c81e6634972b8ca..bd4772a45cdb33d7ebc43296dd19b7f69f003967 100644 --- a/src/mol-model/structure/export/categories/misc.ts +++ b/src/mol-model/structure/export/categories/misc.ts @@ -32,4 +32,14 @@ export const _pdbx_chem_comp_identifier: CifCategory<CifExportContext> = { const indices = Column.indicesOf(comp_id, id => names.has(id)); return CifCategory.ofTable(pdbx_chem_comp_identifier, indices); } +} + +export const _pdbx_nonpoly_scheme: CifCategory<CifExportContext> = { + name: 'pdbx_nonpoly_scheme', + instance({ firstModel, structures, cache }) { + const pdbx_nonpoly_scheme = getModelMmCifCategory(firstModel, 'pdbx_nonpoly_scheme'); + if (!pdbx_nonpoly_scheme) return CifCategory.Empty; + // TODO: filter? + return CifCategory.ofTable(pdbx_nonpoly_scheme); + } } \ No newline at end of file diff --git a/src/mol-model/structure/export/categories/utils.ts b/src/mol-model/structure/export/categories/utils.ts index be0276c94ae628f647ececf34c75e5acf2ac505b..d0a63367f8a4a3c7e472b6feaed0ff32316a4beb 100644 --- a/src/mol-model/structure/export/categories/utils.ts +++ b/src/mol-model/structure/export/categories/utils.ts @@ -11,6 +11,8 @@ import { Structure } from '../../structure'; import { EntityIndex } from '../../model/indexing'; import { UniqueArray } from 'mol-data/generic'; import { sortArray } from 'mol-data/util'; +import { CifWriter } from 'mol-io/writer/cif'; +import { CifExportContext } from '../mmcif'; export function getModelMmCifCategory<K extends keyof mmCIF_Schema>(model: Model, name: K): mmCIF_Database[K] | undefined { if (model.sourceData.kind !== 'mmCIF') return; @@ -39,4 +41,20 @@ export function getUniqueEntityIndicesFromStructures(structures: Structure[]): R } sortArray(ret.array); return ret.array; +} + +export function copy_mmCif_category(name: keyof mmCIF_Schema, condition?: (structure: Structure) => boolean): CifWriter.Category<CifExportContext> { + return { + name, + instance({ structures }) { + if (condition && !condition(structures[0])) return CifWriter.Category.Empty; + + const model = structures[0].model; + if (model.sourceData.kind !== 'mmCIF') return CifWriter.Category.Empty; + + const table = model.sourceData.data[name]; + if (!table || !table._rowCount) return CifWriter.Category.Empty; + return CifWriter.Category.ofTable(table); + } + }; } \ No newline at end of file diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index 40dd6985cc83b2a7ea4f1d14c7347f93083a917d..e0c189ab4afa7088656e3f0312e2539f7335e4de 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -12,9 +12,9 @@ import { _atom_site } from './categories/atom_site'; import CifCategory = CifWriter.Category import { _struct_conf, _struct_sheet_range } from './categories/secondary-structure'; import { _pdbx_struct_mod_residue } from './categories/modified-residues'; -import { _chem_comp, _pdbx_chem_comp_identifier } from './categories/misc'; +import { _chem_comp, _pdbx_chem_comp_identifier, _pdbx_nonpoly_scheme } from './categories/misc'; import { Model } from '../model'; -import { getUniqueEntityIndicesFromStructures } from './categories/utils'; +import { getUniqueEntityIndicesFromStructures, copy_mmCif_category } from './categories/utils'; import { _struct_asym, _entity_poly, _entity_poly_seq } from './categories/sequence'; import { ModelPropertyDescriptor } from '../model/properties/custom'; @@ -35,19 +35,6 @@ export namespace CifExportContext { } } -function copy_mmCif_category(name: keyof mmCIF_Schema): CifCategory<CifExportContext> { - return { - name, - instance({ structures }) { - const model = structures[0].model; - if (model.sourceData.kind !== 'mmCIF') return CifCategory.Empty; - const table = model.sourceData.data[name]; - if (!table || !table._rowCount) return CifCategory.Empty; - return CifCategory.ofTable(table); - } - }; -} - const _entity: CifCategory<CifExportContext> = { name: 'entity', instance({ structures }) { @@ -56,6 +43,10 @@ const _entity: CifCategory<CifExportContext> = { } } +function isWithoutSymmetry(structure: Structure) { + return structure.units.every(u => u.conformation.operator.isIdentity) +} + const Categories = [ // Basics copy_mmCif_category('entry'), @@ -63,13 +54,13 @@ const Categories = [ _entity, // Symmetry - copy_mmCif_category('cell'), - copy_mmCif_category('symmetry'), + copy_mmCif_category('cell', isWithoutSymmetry), + copy_mmCif_category('symmetry', isWithoutSymmetry), // Assemblies - copy_mmCif_category('pdbx_struct_assembly'), - copy_mmCif_category('pdbx_struct_assembly_gen'), - copy_mmCif_category('pdbx_struct_oper_list'), + copy_mmCif_category('pdbx_struct_assembly', isWithoutSymmetry), + copy_mmCif_category('pdbx_struct_assembly_gen', isWithoutSymmetry), + copy_mmCif_category('pdbx_struct_oper_list', isWithoutSymmetry), // Secondary structure _struct_conf, @@ -91,6 +82,7 @@ const Categories = [ _pdbx_chem_comp_identifier, copy_mmCif_category('atom_sites'), + _pdbx_nonpoly_scheme, _pdbx_struct_mod_residue, // Atoms diff --git a/src/servers/model/config.ts b/src/servers/model/config.ts index 50869b603d5ae0ac191c2d8d593b4d2062ac69f6..a441e5085c03cb44da7aba53a31c2ee9e1a043ea 100644 --- a/src/servers/model/config.ts +++ b/src/servers/model/config.ts @@ -81,7 +81,7 @@ const config = { mapFile(source: string, id: string) { switch (source.toLowerCase()) { // case 'pdb': return `e:/test/quick/${id}_updated.cif`; - case 'pdb': return `c:/test/mol-star/model/out/${id}_updated.bcif`; + case 'pdb': return `e:/test/mol-star/model/out/${id}_updated.bcif`; case 'pdb-bcif': return `c:/test/mol-star/model/out/${id}_updated.bcif`; case 'pdb-cif': return `c:/test/mol-star/model/out/${id}_updated.cif`; default: return void 0; diff --git a/src/servers/model/query/atoms.ts b/src/servers/model/query/atoms.ts index 0901023f9e11afe766c3688759b570b2a1b86e6a..4f38ba3d28da5aa2d2530ece44dd0d8484bcd60c 100644 --- a/src/servers/model/query/atoms.ts +++ b/src/servers/model/query/atoms.ts @@ -6,7 +6,7 @@ import { QueryPredicate, StructureElement, StructureProperties as Props } from 'mol-model/structure'; import { AtomsQueryParams } from 'mol-model/structure/query/queries/generators'; -import { AtomSiteSchema } from '../server/api'; +import { AtomSiteSchema, AtomSiteSchemaElement } from '../server/api'; export function getAtomsTests(params: AtomSiteSchema): Partial<AtomsQueryParams>[] { if (!params) return [{ }]; @@ -17,7 +17,7 @@ export function getAtomsTests(params: AtomSiteSchema): Partial<AtomsQueryParams> } } -function atomsTest(params: AtomSiteSchema): Partial<AtomsQueryParams> { +function atomsTest(params: AtomSiteSchemaElement): Partial<AtomsQueryParams> { return { entityTest: entityTest(params), chainTest: chainTest(params), @@ -26,13 +26,13 @@ function atomsTest(params: AtomSiteSchema): Partial<AtomsQueryParams> { }; } -function entityTest(params: AtomSiteSchema): QueryPredicate | undefined { +function entityTest(params: AtomSiteSchemaElement): QueryPredicate | undefined { if (!params || typeof params.label_entity_id === 'undefined') return void 0; const p = Props.entity.id, id = '' + params.label_entity_id; return ctx => p(ctx.element) === id; } -function chainTest(params: AtomSiteSchema): QueryPredicate | undefined { +function chainTest(params: AtomSiteSchemaElement): QueryPredicate | undefined { if (!params) return void 0; if (typeof params.label_asym_id !== 'undefined') { @@ -46,7 +46,7 @@ function chainTest(params: AtomSiteSchema): QueryPredicate | undefined { return void 0; } -function residueTest(params: AtomSiteSchema): QueryPredicate | undefined { +function residueTest(params: AtomSiteSchemaElement): QueryPredicate | undefined { if (!params) return void 0; const props: StructureElement.Property<any>[] = [], values: any[] = []; @@ -79,7 +79,7 @@ function residueTest(params: AtomSiteSchema): QueryPredicate | undefined { return andEqual(props, values); } -function atomTest(params: AtomSiteSchema): QueryPredicate | undefined { +function atomTest(params: AtomSiteSchemaElement): QueryPredicate | undefined { if (!params) return void 0; const props: StructureElement.Property<any>[] = [], values: any[] = []; diff --git a/src/servers/model/server/api.ts b/src/servers/model/server/api.ts index ac0e7147cf6e0eb038e0d77aaf2a91b8baf61317..ced5f70163b88405cd57d6bcb47cdf4781a671fc 100644 --- a/src/servers/model/server/api.ts +++ b/src/servers/model/server/api.ts @@ -35,7 +35,7 @@ export interface QueryDefinition<Params = any> { '@params': Params } -export interface AtomSiteSchema { +export interface AtomSiteSchemaElement { label_entity_id?: string, label_asym_id?: string, @@ -52,6 +52,8 @@ export interface AtomSiteSchema { type_symbol?: string } +export type AtomSiteSchema = AtomSiteSchemaElement | AtomSiteSchemaElement[] + const AtomSiteTestParams: QueryParamInfo = { name: 'atom_site', type: QueryParamType.JSON, @@ -126,6 +128,16 @@ const QueryMap = { }, params: [ AtomSiteTestParams, RadiusParam ] }), + 'residueSurroundings': Q<{ atom_site: AtomSiteSchema, radius: number }>({ + niceName: 'Residue Surroundings', + description: 'Identifies all residues within the given radius from the source residue.', + query(p) { + const tests = getAtomsTests(p.atom_site); + const center = Queries.combinators.merge(tests.map(test => Queries.generators.atoms(test))); + return Queries.modifiers.includeSurroundings(center, { radius: p.radius, wholeResidues: true }); + }, + params: [ AtomSiteTestParams, RadiusParam ] + }) }; export type QueryName = keyof typeof QueryMap