diff --git a/src/apps/structure-info/model.ts b/src/apps/structure-info/model.ts index 9c7f0d9a9876f39c78cd5887f9696ef377c1ea4b..85f118dea62635a631fdf061429976276887b339 100644 --- a/src/apps/structure-info/model.ts +++ b/src/apps/structure-info/model.ts @@ -72,20 +72,45 @@ export function printSecStructure(model: Model) { } } -export function printBonds(structure: Structure) { - for (const unit of structure.units) { - if (!Unit.isAtomic(unit)) continue; +export function printLinks(structure: Structure, showIntra: boolean, showInter: boolean) { + if (showIntra) { + console.log('\nIntra Unit Links\n============='); + for (const unit of structure.units) { + if (!Unit.isAtomic(unit)) continue; + + const elements = unit.elements; + const { a, b } = unit.links; + const { model } = unit; + + if (!a.length) continue; + + for (let bI = 0, _bI = a.length; bI < _bI; bI++) { + const x = a[bI], y = b[bI]; + if (x >= y) continue; + console.log(`${atomLabel(model, elements[x])} -- ${atomLabel(model, elements[y])}`); + } + } + } - const elements = unit.elements; - const { a, b } = unit.bonds; - const { model } = unit; + if (showInter) { + console.log('\nInter Unit Links\n============='); + const links = structure.links; + for (const unit of structure.units) { + if (!Unit.isAtomic(unit)) continue; + + for (const pairLinks of links.getLinkedUnits(unit)) { + if (!pairLinks.areUnitsOrdered) continue; - if (!a.length) continue; + const { unitA, unitB } = pairLinks; - for (let bI = 0, _bI = a.length; bI < _bI; bI++) { - const x = a[bI], y = b[bI]; - if (x >= y) continue; - console.log(`${atomLabel(model, elements[x])} -- ${atomLabel(model, elements[y])}`); + console.log(`${pairLinks.unitA.id} - ${pairLinks.unitB.id}: ${pairLinks.bondCount} bond(s)`); + + for (const aI of pairLinks.linkedElementIndices) { + for (const link of pairLinks.getBonds(aI)) { + console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[link.indexB])}`); + } + } + } } } } @@ -160,7 +185,7 @@ async function run(mmcif: mmCIF_Database) { //printIHMModels(models[0]); printUnits(structure); printRings(structure); - //printBonds(structure); + printLinks(structure, false, true); //printSecStructure(models[0]); } @@ -175,13 +200,13 @@ async function runFile(filename: string) { } const parser = new argparse.ArgumentParser({ - addHelp: true, - description: 'Print info about a structure, mainly to test and showcase the mol-model module' + addHelp: true, + description: 'Print info about a structure, mainly to test and showcase the mol-model module' }); -parser.addArgument([ '--download', '-d' ], { +parser.addArgument(['--download', '-d'], { help: 'Pdb entry id' }); -parser.addArgument([ '--file', '-f' ], { +parser.addArgument(['--file', '-f'], { help: 'filename' }); interface Args { diff --git a/src/mol-geo/representation/structure/bond.ts b/src/mol-geo/representation/structure/bond.ts index afb2cf89c183e25db5c24fa9f47efa2d7784f8ad..d4a30eea3782caabe13842b41d3190757d578369 100644 --- a/src/mol-geo/representation/structure/bond.ts +++ b/src/mol-geo/representation/structure/bond.ts @@ -8,7 +8,7 @@ import { ValueCell } from 'mol-util/value-cell' import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' -import { Unit, Element, Bond } from 'mol-model/structure'; +import { Unit, Element, Link } from 'mol-model/structure'; import { UnitsRepresentation, DefaultStructureProps } from './index'; import { Task } from 'mol-task' import { createTransforms } from './utils'; @@ -29,7 +29,7 @@ function createBondMesh(unit: Unit, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) const elements = unit.elements; - const bonds = unit.bonds + const bonds = unit.links const { edgeCount, a, b } = bonds if (!edgeCount) return Mesh.createEmpty(mesh) @@ -96,7 +96,7 @@ export default function BondUnitsRepresentation(): UnitsRepresentation<BondProps currentGroup = group const unit = group.units[0] - const elementCount = Unit.isAtomic(unit) ? unit.bonds.edgeCount * 2 : 0 + const elementCount = Unit.isAtomic(unit) ? unit.links.edgeCount * 2 : 0 const instanceCount = group.units.length mesh = await createBondMesh(unit).runAsChild(ctx, 'Computing bond mesh') @@ -164,11 +164,11 @@ export default function BondUnitsRepresentation(): UnitsRepresentation<BondProps const { objectId, instanceId, elementId } = pickingId const unit = currentGroup.units[instanceId] if (cylinders.id === objectId && Unit.isAtomic(unit)) { - return Bond.Loci([{ + return Link.Loci([{ aUnit: unit, - aIndex: unit.bonds.a[elementId], + aIndex: unit.links.a[elementId], bUnit: unit, - bIndex: unit.bonds.b[elementId] + bIndex: unit.links.b[elementId] }]) } return null @@ -179,7 +179,7 @@ export default function BondUnitsRepresentation(): UnitsRepresentation<BondProps const unit = group.units[0] if (!Unit.isAtomic(unit)) return - const elementCount = unit.bonds.edgeCount * 2 + const elementCount = unit.links.edgeCount * 2 const instanceCount = group.units.length let changed = false @@ -187,11 +187,11 @@ export default function BondUnitsRepresentation(): UnitsRepresentation<BondProps if (isEveryLoci(loci)) { applyFlagAction(array, 0, elementCount * instanceCount, action) changed = true - } else if (Bond.isLoci(loci)) { - for (const b of loci.bonds) { + } else if (Link.isLoci(loci)) { + for (const b of loci.links) { const unitIdx = Unit.findUnitById(b.aUnit.id, group.units) if (unitIdx !== -1) { - const _idx = unit.bonds.getEdgeIndex(b.aIndex, b.bIndex) + const _idx = unit.links.getEdgeIndex(b.aIndex, b.bIndex) if (_idx !== -1) { const idx = _idx if (applyFlagAction(array, idx, idx + 1, action) && !changed) { diff --git a/src/mol-math/graph.ts b/src/mol-math/graph.ts index f152b30c290df2178546c272a5008bb6f9ce65ae..f1e24c2f39e5cbaef4ae6e7c6f8e5d1ed5dc9f05 100644 --- a/src/mol-math/graph.ts +++ b/src/mol-math/graph.ts @@ -4,4 +4,4 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -export * from './graph/int-graph' \ No newline at end of file +export * from './graph/int-adjacency-graph' \ No newline at end of file diff --git a/src/mol-math/graph/_spec/int-graph.spec.ts b/src/mol-math/graph/_spec/int-graph.spec.ts index 25319d11850f360bc3420b0dfc1ff6c9ecdff965..5d0315e658ef3e3662a08149f8d10b18cfe770ba 100644 --- a/src/mol-math/graph/_spec/int-graph.spec.ts +++ b/src/mol-math/graph/_spec/int-graph.spec.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { IntGraph } from '../int-graph'; +import { IntAdjacencyGraph } from '../int-adjacency-graph'; describe('IntGraph', () => { const vc = 3; @@ -12,7 +12,7 @@ describe('IntGraph', () => { const ys = [1, 2, 0]; const _prop = [10, 11, 12]; - const builder = new IntGraph.EdgeBuilder(vc, xs, ys); + const builder = new IntAdjacencyGraph.EdgeBuilder(vc, xs, ys); const prop: number[] = new Array(builder.slotCount); for (let i = 0; i < builder.edgeCount; i++) { builder.addNextEdge(); @@ -35,7 +35,7 @@ describe('IntGraph', () => { }); it('induce', () => { - const induced = IntGraph.induceByVertices(graph, [1, 2]); + const induced = IntAdjacencyGraph.induceByVertices(graph, [1, 2]); expect(induced.vertexCount).toBe(2); expect(induced.edgeCount).toBe(1); expect(induced.edgeProps.prop[induced.getEdgeIndex(0, 1)]).toBe(11); diff --git a/src/mol-math/graph/int-graph.ts b/src/mol-math/graph/int-adjacency-graph.ts similarity index 88% rename from src/mol-math/graph/int-graph.ts rename to src/mol-math/graph/int-adjacency-graph.ts index 601196214baae16264b22823d262b0e33e9879b5..8b5af369dbd1e71e6e166311c67d61bb11036d77 100644 --- a/src/mol-math/graph/int-graph.ts +++ b/src/mol-math/graph/int-adjacency-graph.ts @@ -1,11 +1,11 @@ -import { arrayPickIndices } from 'mol-data/util'; - /** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ +import { arrayPickIndices } from 'mol-data/util'; + /** * Represent a graph using vertex adjacency list. * @@ -14,7 +14,7 @@ import { arrayPickIndices } from 'mol-data/util'; * * Edge properties are indexed same as in the arrays a and b. */ -interface IntGraph<EdgeProps extends IntGraph.EdgePropsBase = {}> { +interface IntAdjacencyGraph<EdgeProps extends IntAdjacencyGraph.EdgePropsBase = {}> { readonly offset: ArrayLike<number>, readonly a: ArrayLike<number>, readonly b: ArrayLike<number>, @@ -33,10 +33,10 @@ interface IntGraph<EdgeProps extends IntGraph.EdgePropsBase = {}> { getVertexEdgeCount(i: number): number } -namespace IntGraph { +namespace IntAdjacencyGraph { export type EdgePropsBase = { [name: string]: ArrayLike<any> } - class IntGraphImpl implements IntGraph<any> { + class IntGraphImpl implements IntAdjacencyGraph<any> { readonly vertexCount: number; readonly edgeProps: object; @@ -60,8 +60,8 @@ namespace IntGraph { } } - export function create<EdgeProps extends IntGraph.EdgePropsBase = {}>(offset: ArrayLike<number>, a: ArrayLike<number>, b: ArrayLike<number>, edgeCount: number, edgeProps?: EdgeProps): IntGraph<EdgeProps> { - return new IntGraphImpl(offset, a, b, edgeCount, edgeProps) as IntGraph<EdgeProps>; + export function create<EdgeProps extends IntAdjacencyGraph.EdgePropsBase = {}>(offset: ArrayLike<number>, a: ArrayLike<number>, b: ArrayLike<number>, edgeCount: number, edgeProps?: EdgeProps): IntAdjacencyGraph<EdgeProps> { + return new IntGraphImpl(offset, a, b, edgeCount, edgeProps) as IntAdjacencyGraph<EdgeProps>; } export class EdgeBuilder { @@ -77,7 +77,7 @@ namespace IntGraph { a: Int32Array; b: Int32Array; - createGraph<EdgeProps extends IntGraph.EdgePropsBase = {}>(edgeProps?: EdgeProps) { + createGraph<EdgeProps extends IntAdjacencyGraph.EdgePropsBase = {}>(edgeProps?: EdgeProps) { return create(this.offsets, this.a, this.b, this.edgeCount, edgeProps); } @@ -135,7 +135,7 @@ namespace IntGraph { } } - export function induceByVertices<P extends IntGraph.EdgePropsBase>(graph: IntGraph<P>, vertexIndices: ArrayLike<number>): IntGraph<P> { + export function induceByVertices<P extends IntAdjacencyGraph.EdgePropsBase>(graph: IntAdjacencyGraph<P>, vertexIndices: ArrayLike<number>): IntAdjacencyGraph<P> { const { b, offset, vertexCount, edgeProps } = graph; const vertexMap = new Int32Array(vertexCount); for (let i = 0, _i = vertexIndices.length; i < _i; i++) vertexMap[vertexIndices[i]] = i + 1; @@ -177,4 +177,4 @@ namespace IntGraph { } } -export { IntGraph } \ No newline at end of file +export { IntAdjacencyGraph } \ No newline at end of file diff --git a/src/mol-model/loci.ts b/src/mol-model/loci.ts index 3d10cb93063593a236d649b6a2911b492c00d300..586ee66d308c5835340cb233bcfa78125f32487b 100644 --- a/src/mol-model/loci.ts +++ b/src/mol-model/loci.ts @@ -5,7 +5,7 @@ */ import { Element } from './structure' -import { Bond } from './structure/structure/unit/bonds' +import { Link } from './structure/structure/unit/links' /** A Loci that includes every loci */ export const EveryLoci = { kind: 'every-loci' as 'every-loci' } @@ -14,4 +14,4 @@ export function isEveryLoci(x: any): x is EveryLoci { return !!x && x.kind === 'every-loci'; } -export type Loci = Element.Loci | Bond.Loci | EveryLoci \ No newline at end of file +export type Loci = Element.Loci | Link.Loci | EveryLoci \ No newline at end of file diff --git a/src/mol-model/structure/model/formats/mmcif/bonds.ts b/src/mol-model/structure/model/formats/mmcif/bonds.ts index 89abf70d400bf0da529f3841d875bbfbd83a968f..85dca86ac533fb4b06c00f1f4c9ce31884b77998 100644 --- a/src/mol-model/structure/model/formats/mmcif/bonds.ts +++ b/src/mol-model/structure/model/formats/mmcif/bonds.ts @@ -6,72 +6,82 @@ */ import Model from '../../model' -import { BondType } from '../../types' +import { LinkType } from '../../types' import { findEntityIdByAsymId, findAtomIndexByLabelName } from './util' import { Column } from 'mol-data/db' -import { IntraUnitBonds } from '../../../structure/unit/bonds'; -export class StructConn implements IntraUnitBonds.StructConn { - private _residuePairIndex: Map<string, StructConn.Entry[]> | undefined = void 0; - private _atomIndex: Map<number, StructConn.Entry[]> | undefined = void 0; +export interface StructConn { + getResidueEntries(residueAIndex: number, residueBIndex: number): ReadonlyArray<StructConn.Entry> + getAtomEntries(atomIndex: number): ReadonlyArray<StructConn.Entry> +} + +export interface ComponentBondInfo { + entries: Map<string, ComponentBondInfo.Entry> +} - private static _resKey(rA: number, rB: number) { +export namespace StructConn { + function _resKey(rA: number, rB: number) { if (rA < rB) return `${rA}-${rB}`; return `${rB}-${rA}`; } - - private getResiduePairIndex() { - if (this._residuePairIndex) return this._residuePairIndex; - this._residuePairIndex = new Map(); - for (const e of this.entries) { - const ps = e.partners; - const l = ps.length; - for (let i = 0; i < l - 1; i++) { - for (let j = i + i; j < l; j++) { - const key = StructConn._resKey(ps[i].residueIndex, ps[j].residueIndex); - if (this._residuePairIndex.has(key)) { - this._residuePairIndex.get(key)!.push(e); - } else { - this._residuePairIndex.set(key, [e]); + const _emptyEntry: Entry[] = []; + + class StructConnImpl implements StructConn { + private _residuePairIndex: Map<string, StructConn.Entry[]> | undefined = void 0; + private _atomIndex: Map<number, StructConn.Entry[]> | undefined = void 0; + + private getResiduePairIndex() { + if (this._residuePairIndex) return this._residuePairIndex; + this._residuePairIndex = new Map(); + for (const e of this.entries) { + const ps = e.partners; + const l = ps.length; + for (let i = 0; i < l - 1; i++) { + for (let j = i + i; j < l; j++) { + const key = _resKey(ps[i].residueIndex, ps[j].residueIndex); + if (this._residuePairIndex.has(key)) { + this._residuePairIndex.get(key)!.push(e); + } else { + this._residuePairIndex.set(key, [e]); + } } } } + return this._residuePairIndex; } - return this._residuePairIndex; - } - private getAtomIndex() { - if (this._atomIndex) return this._atomIndex; - this._atomIndex = new Map(); - for (const e of this.entries) { - for (const p of e.partners) { - const key = p.atomIndex; - if (this._atomIndex.has(key)) { - this._atomIndex.get(key)!.push(e); - } else { - this._atomIndex.set(key, [e]); + private getAtomIndex() { + if (this._atomIndex) return this._atomIndex; + this._atomIndex = new Map(); + for (const e of this.entries) { + for (const p of e.partners) { + const key = p.atomIndex; + if (this._atomIndex.has(key)) { + this._atomIndex.get(key)!.push(e); + } else { + this._atomIndex.set(key, [e]); + } } } + return this._atomIndex; } - return this._atomIndex; - } - private static _emptyEntry = []; - getResidueEntries(residueAIndex: number, residueBIndex: number): ReadonlyArray<StructConn.Entry> { - return this.getResiduePairIndex().get(StructConn._resKey(residueAIndex, residueBIndex)) || StructConn._emptyEntry; - } + getResidueEntries(residueAIndex: number, residueBIndex: number): ReadonlyArray<StructConn.Entry> { + return this.getResiduePairIndex().get(_resKey(residueAIndex, residueBIndex)) || _emptyEntry; + } - getAtomEntries(atomIndex: number): ReadonlyArray<StructConn.Entry> { - return this.getAtomIndex().get(atomIndex) || StructConn._emptyEntry; - } + getAtomEntries(atomIndex: number): ReadonlyArray<StructConn.Entry> { + return this.getAtomIndex().get(atomIndex) || _emptyEntry; + } - constructor(public entries: StructConn.Entry[]) { + constructor(public entries: StructConn.Entry[]) { + } } -} -export namespace StructConn { - export interface Entry extends IntraUnitBonds.StructConnEntry { + + + export interface Entry { distance: number, order: number, flags: number, @@ -91,7 +101,7 @@ export namespace StructConn { | 'saltbr' export function create(model: Model): StructConn | undefined { - if (model.sourceData.kind !== 'mmCIF') return + if (model.sourceData.kind !== 'mmCIF') return; const { struct_conn } = model.sourceData.data; if (!struct_conn._rowCount) return void 0; @@ -150,7 +160,7 @@ export namespace StructConn { const type = conn_type_id.value(i)! as StructConnType; const orderType = (pdbx_value_order.value(i) || '').toLowerCase(); - let flags = BondType.Flag.None; + let flags = LinkType.Flag.None; let order = 1; switch (orderType) { @@ -166,22 +176,22 @@ export namespace StructConn { case 'covale_phosphate': case 'covale_sugar': case 'modres': - flags = BondType.Flag.Covalent; + flags = LinkType.Flag.Covalent; break; - case 'disulf': flags = BondType.Flag.Covalent | BondType.Flag.Sulfide; break; - case 'hydrog': flags = BondType.Flag.Hydrogen; break; - case 'metalc': flags = BondType.Flag.MetallicCoordination; break; - case 'saltbr': flags = BondType.Flag.Ion; break; + case 'disulf': flags = LinkType.Flag.Covalent | LinkType.Flag.Sulfide; break; + case 'hydrog': flags = LinkType.Flag.Hydrogen; break; + case 'metalc': flags = LinkType.Flag.MetallicCoordination; break; + case 'saltbr': flags = LinkType.Flag.Ion; break; } entries.push({ flags, order, distance: pdbx_dist_value.value(i), partners }); } - return new StructConn(entries); + return new StructConnImpl(entries); } } -export class ComponentBondInfo implements IntraUnitBonds.ComponentBondInfo { +export class ComponentBondInfo implements ComponentBondInfo { entries: Map<string, ComponentBondInfo.Entry> = new Map(); newEntry(id: string) { @@ -192,7 +202,7 @@ export class ComponentBondInfo implements IntraUnitBonds.ComponentBondInfo { } export namespace ComponentBondInfo { - export class Entry implements IntraUnitBonds.ComponentBondInfoEntry { + export class Entry implements Entry { map: Map<string, Map<string, { order: number, flags: number }>> = new Map(); add(a: string, b: string, order: number, flags: number, swap = true) { @@ -238,9 +248,9 @@ export namespace ComponentBondInfo { entry = info.newEntry(id); } - let flags: number = BondType.Flag.Covalent; + let flags: number = LinkType.Flag.Covalent; let ord = 1; - if (aromatic) flags |= BondType.Flag.Aromatic; + if (aromatic) flags |= LinkType.Flag.Aromatic; switch (order.toLowerCase()) { case 'doub': case 'delo': diff --git a/src/mol-model/structure/model/types.ts b/src/mol-model/structure/model/types.ts index 36d0cb935f3631e5fd0057526443f753472090f6..16c748b99b1d3d38f4a88614837ae8658acaed94 100644 --- a/src/mol-model/structure/model/types.ts +++ b/src/mol-model/structure/model/types.ts @@ -340,9 +340,9 @@ export const VdwRadii = { } export const DefaultVdwRadius = 2.0 -export interface BondType extends BitFlags<BondType.Flag> { } -export namespace BondType { - export const is: (b: BondType, f: Flag) => boolean = BitFlags.has +export interface LinkType extends BitFlags<LinkType.Flag> { } +export namespace LinkType { + export const is: (b: LinkType, f: Flag) => boolean = BitFlags.has export const enum Flag { None = 0x0, Covalent = 0x1, @@ -354,4 +354,8 @@ export namespace BondType { Computed = 0x40 // currently at most 16 flags are supported!! } + + export function isCovalent(flags: LinkType.Flag) { + return (flags & LinkType.Flag.Covalent) !== 0; + } } \ No newline at end of file diff --git a/src/mol-model/structure/structure.ts b/src/mol-model/structure/structure.ts index 44a299b2e5c3a9c41148e6298e8fc5488fb8c04d..bed8ae1fd045532d92ac1922e95cfdcd5b5afc04 100644 --- a/src/mol-model/structure/structure.ts +++ b/src/mol-model/structure/structure.ts @@ -8,6 +8,6 @@ import Element from './structure/element' import Structure from './structure/structure' import Unit from './structure/unit' import StructureSymmetry from './structure/symmetry' -import { Bond } from './structure/unit/bonds' +import { Link } from './structure/unit/links' -export { Element, Bond, Structure, Unit, StructureSymmetry } \ No newline at end of file +export { Element, Link, Structure, Unit, StructureSymmetry } \ No newline at end of file diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index cac54e0b559c6f488ad7541915907a1e5a57f061..52239bb46877b7f53cb2361fbe7345a60d445e57 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -15,6 +15,7 @@ import { StructureLookup3D } from './util/lookup3d'; import { CoarseElements } from '../model/properties/coarse'; import { StructureSubsetBuilder } from './util/subset-builder'; import { Queries } from '../query'; +import { InterUnitBonds, computeInterUnitBonds } from './unit/links'; class Structure { readonly unitMap: IntMap<Unit>; @@ -60,6 +61,13 @@ class Structure { return this._lookup3d; } + private _links?: InterUnitBonds = void 0; + get links() { + if (this._links) return this._links; + this._links = computeInterUnitBonds(this); + return this._links; + } + constructor(units: ArrayLike<Unit>) { const map = IntMap.Mutable<Unit>(); let elementCount = 0; diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index e5ef8d9080ebf11d6b2b5b6e6f2a76353aee9a61..c5488a09bc76f1393318cc1b9c5620998a8daa8f 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/src/mol-model/structure/structure/unit.ts @@ -9,7 +9,7 @@ import { Model } from '../model' import { GridLookup3D, Lookup3D } from 'mol-math/geometry' import { SortedArray } from 'mol-data/int'; import { idFactory } from 'mol-util/id-factory'; -import { IntraUnitBonds, computeIntraUnitBonds } from './unit/bonds' +import { IntraUnitLinks, computeIntraUnitBonds } from './unit/links' import { CoarseElements, CoarseSphereConformation, CoarseGaussianConformation } from '../model/properties/coarse'; import { ValueRef } from 'mol-util'; import { UnitRings } from './unit/rings'; @@ -100,10 +100,10 @@ namespace Unit { return this.props.lookup3d.ref; } - get bonds() { - if (this.props.bonds.ref) return this.props.bonds.ref; - this.props.bonds.ref = computeIntraUnitBonds(this); - return this.props.bonds.ref; + get links() { + if (this.props.links.ref) return this.props.links.ref; + this.props.links.ref = computeIntraUnitBonds(this); + return this.props.links.ref; } get rings() { @@ -127,12 +127,12 @@ namespace Unit { interface AtomicProperties { lookup3d: ValueRef<Lookup3D | undefined>, - bonds: ValueRef<IntraUnitBonds | undefined>, + links: ValueRef<IntraUnitLinks | undefined>, rings: ValueRef<UnitRings | undefined> } - function AtomicProperties() { - return { lookup3d: ValueRef.create(void 0), bonds: ValueRef.create(void 0), rings: ValueRef.create(void 0) }; + function AtomicProperties(): AtomicProperties { + return { lookup3d: ValueRef.create(void 0), links: ValueRef.create(void 0), rings: ValueRef.create(void 0) }; } class Coarse<K extends Kind.Gaussians | Kind.Spheres, C extends CoarseSphereConformation | CoarseGaussianConformation> implements Base { diff --git a/src/mol-model/structure/structure/unit/bonds/data.ts b/src/mol-model/structure/structure/unit/bonds/data.ts deleted file mode 100644 index 0ffdd02fcbce683e436c0030ffe0517135c6ceda..0000000000000000000000000000000000000000 --- a/src/mol-model/structure/structure/unit/bonds/data.ts +++ /dev/null @@ -1 +0,0 @@ -// TODO \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts deleted file mode 100644 index 0ffdd02fcbce683e436c0030ffe0517135c6ceda..0000000000000000000000000000000000000000 --- a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts +++ /dev/null @@ -1 +0,0 @@ -// TODO \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/bonds/inter-data.ts b/src/mol-model/structure/structure/unit/bonds/inter-data.ts deleted file mode 100644 index 0ffdd02fcbce683e436c0030ffe0517135c6ceda..0000000000000000000000000000000000000000 --- a/src/mol-model/structure/structure/unit/bonds/inter-data.ts +++ /dev/null @@ -1 +0,0 @@ -// TODO \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts deleted file mode 100644 index ba344073c94604ba612a5dfafe4bd100770e30bb..0000000000000000000000000000000000000000 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ /dev/null @@ -1,214 +0,0 @@ -/** - * Copyright (c) 2017 Mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -import { BondType, ElementSymbol } from '../../../model/types' -import { IntraUnitBonds } from './intra-data' -import { StructConn, ComponentBondInfo } from '../../../model/formats/mmcif/bonds' -import Unit from '../../unit' -import { IntGraph } from 'mol-math/graph'; - -export interface BondComputationParameters { - maxHbondLength: number, - forceCompute: boolean -} - -// H,D,T are all mapped to H -const __ElementIndex: { [e: string]: number | undefined } = { 'H': 0, 'h': 0, 'D': 0, 'd': 0, 'T': 0, 't': 0, 'He': 2, 'HE': 2, 'he': 2, 'Li': 3, 'LI': 3, 'li': 3, 'Be': 4, 'BE': 4, 'be': 4, 'B': 5, 'b': 5, 'C': 6, 'c': 6, 'N': 7, 'n': 7, 'O': 8, 'o': 8, 'F': 9, 'f': 9, 'Ne': 10, 'NE': 10, 'ne': 10, 'Na': 11, 'NA': 11, 'na': 11, 'Mg': 12, 'MG': 12, 'mg': 12, 'Al': 13, 'AL': 13, 'al': 13, 'Si': 14, 'SI': 14, 'si': 14, 'P': 15, 'p': 15, 'S': 16, 's': 16, 'Cl': 17, 'CL': 17, 'cl': 17, 'Ar': 18, 'AR': 18, 'ar': 18, 'K': 19, 'k': 19, 'Ca': 20, 'CA': 20, 'ca': 20, 'Sc': 21, 'SC': 21, 'sc': 21, 'Ti': 22, 'TI': 22, 'ti': 22, 'V': 23, 'v': 23, 'Cr': 24, 'CR': 24, 'cr': 24, 'Mn': 25, 'MN': 25, 'mn': 25, 'Fe': 26, 'FE': 26, 'fe': 26, 'Co': 27, 'CO': 27, 'co': 27, 'Ni': 28, 'NI': 28, 'ni': 28, 'Cu': 29, 'CU': 29, 'cu': 29, 'Zn': 30, 'ZN': 30, 'zn': 30, 'Ga': 31, 'GA': 31, 'ga': 31, 'Ge': 32, 'GE': 32, 'ge': 32, 'As': 33, 'AS': 33, 'as': 33, 'Se': 34, 'SE': 34, 'se': 34, 'Br': 35, 'BR': 35, 'br': 35, 'Kr': 36, 'KR': 36, 'kr': 36, 'Rb': 37, 'RB': 37, 'rb': 37, 'Sr': 38, 'SR': 38, 'sr': 38, 'Y': 39, 'y': 39, 'Zr': 40, 'ZR': 40, 'zr': 40, 'Nb': 41, 'NB': 41, 'nb': 41, 'Mo': 42, 'MO': 42, 'mo': 42, 'Tc': 43, 'TC': 43, 'tc': 43, 'Ru': 44, 'RU': 44, 'ru': 44, 'Rh': 45, 'RH': 45, 'rh': 45, 'Pd': 46, 'PD': 46, 'pd': 46, 'Ag': 47, 'AG': 47, 'ag': 47, 'Cd': 48, 'CD': 48, 'cd': 48, 'In': 49, 'IN': 49, 'in': 49, 'Sn': 50, 'SN': 50, 'sn': 50, 'Sb': 51, 'SB': 51, 'sb': 51, 'Te': 52, 'TE': 52, 'te': 52, 'I': 53, 'i': 53, 'Xe': 54, 'XE': 54, 'xe': 54, 'Cs': 55, 'CS': 55, 'cs': 55, 'Ba': 56, 'BA': 56, 'ba': 56, 'La': 57, 'LA': 57, 'la': 57, 'Ce': 58, 'CE': 58, 'ce': 58, 'Pr': 59, 'PR': 59, 'pr': 59, 'Nd': 60, 'ND': 60, 'nd': 60, 'Pm': 61, 'PM': 61, 'pm': 61, 'Sm': 62, 'SM': 62, 'sm': 62, 'Eu': 63, 'EU': 63, 'eu': 63, 'Gd': 64, 'GD': 64, 'gd': 64, 'Tb': 65, 'TB': 65, 'tb': 65, 'Dy': 66, 'DY': 66, 'dy': 66, 'Ho': 67, 'HO': 67, 'ho': 67, 'Er': 68, 'ER': 68, 'er': 68, 'Tm': 69, 'TM': 69, 'tm': 69, 'Yb': 70, 'YB': 70, 'yb': 70, 'Lu': 71, 'LU': 71, 'lu': 71, 'Hf': 72, 'HF': 72, 'hf': 72, 'Ta': 73, 'TA': 73, 'ta': 73, 'W': 74, 'w': 74, 'Re': 75, 'RE': 75, 're': 75, 'Os': 76, 'OS': 76, 'os': 76, 'Ir': 77, 'IR': 77, 'ir': 77, 'Pt': 78, 'PT': 78, 'pt': 78, 'Au': 79, 'AU': 79, 'au': 79, 'Hg': 80, 'HG': 80, 'hg': 80, 'Tl': 81, 'TL': 81, 'tl': 81, 'Pb': 82, 'PB': 82, 'pb': 82, 'Bi': 83, 'BI': 83, 'bi': 83, 'Po': 84, 'PO': 84, 'po': 84, 'At': 85, 'AT': 85, 'at': 85, 'Rn': 86, 'RN': 86, 'rn': 86, 'Fr': 87, 'FR': 87, 'fr': 87, 'Ra': 88, 'RA': 88, 'ra': 88, 'Ac': 89, 'AC': 89, 'ac': 89, 'Th': 90, 'TH': 90, 'th': 90, 'Pa': 91, 'PA': 91, 'pa': 91, 'U': 92, 'u': 92, 'Np': 93, 'NP': 93, 'np': 93, 'Pu': 94, 'PU': 94, 'pu': 94, 'Am': 95, 'AM': 95, 'am': 95, 'Cm': 96, 'CM': 96, 'cm': 96, 'Bk': 97, 'BK': 97, 'bk': 97, 'Cf': 98, 'CF': 98, 'cf': 98, 'Es': 99, 'ES': 99, 'es': 99, 'Fm': 100, 'FM': 100, 'fm': 100, 'Md': 101, 'MD': 101, 'md': 101, 'No': 102, 'NO': 102, 'no': 102, 'Lr': 103, 'LR': 103, 'lr': 103, 'Rf': 104, 'RF': 104, 'rf': 104, 'Db': 105, 'DB': 105, 'db': 105, 'Sg': 106, 'SG': 106, 'sg': 106, 'Bh': 107, 'BH': 107, 'bh': 107, 'Hs': 108, 'HS': 108, 'hs': 108, 'Mt': 109, 'MT': 109, 'mt': 109 }; - -const __ElementBondThresholds: { [e: number]: number | undefined } = { 0: 1.42, 1: 1.42, 3: 2.7, 4: 2.7, 6: 1.75, 7: 1.6, 8: 1.52, 11: 2.7, 12: 2.7, 13: 2.7, 14: 1.9, 15: 1.9, 16: 1.9, 17: 1.8, 19: 2.7, 20: 2.7, 21: 2.7, 22: 2.7, 23: 2.7, 24: 2.7, 25: 2.7, 26: 2.7, 27: 2.7, 28: 2.7, 29: 2.7, 30: 2.7, 31: 2.7, 33: 2.68, 37: 2.7, 38: 2.7, 39: 2.7, 40: 2.7, 41: 2.7, 42: 2.7, 43: 2.7, 44: 2.7, 45: 2.7, 46: 2.7, 47: 2.7, 48: 2.7, 49: 2.7, 50: 2.7, 55: 2.7, 56: 2.7, 57: 2.7, 58: 2.7, 59: 2.7, 60: 2.7, 61: 2.7, 62: 2.7, 63: 2.7, 64: 2.7, 65: 2.7, 66: 2.7, 67: 2.7, 68: 2.7, 69: 2.7, 70: 2.7, 71: 2.7, 72: 2.7, 73: 2.7, 74: 2.7, 75: 2.7, 76: 2.7, 77: 2.7, 78: 2.7, 79: 2.7, 80: 2.7, 81: 2.7, 82: 2.7, 83: 2.7, 87: 2.7, 88: 2.7, 89: 2.7, 90: 2.7, 91: 2.7, 92: 2.7, 93: 2.7, 94: 2.7, 95: 2.7, 96: 2.7, 97: 2.7, 98: 2.7, 99: 2.7, 100: 2.7, 101: 2.7, 102: 2.7, 103: 2.7, 104: 2.7, 105: 2.7, 106: 2.7, 107: 2.7, 108: 2.7, 109: 2.88 }; - -const __ElementPairThresholds: { [e: number]: number | undefined } = { 0: 0.8, 20: 1.31, 27: 1.3, 35: 1.3, 44: 1.05, 54: 1, 60: 1.84, 72: 1.88, 84: 1.75, 85: 1.56, 86: 1.76, 98: 1.6, 99: 1.68, 100: 1.63, 112: 1.55, 113: 1.59, 114: 1.36, 129: 1.45, 144: 1.6, 170: 1.4, 180: 1.55, 202: 2.4, 222: 2.24, 224: 1.91, 225: 1.98, 243: 2.02, 269: 2, 293: 1.9, 480: 2.3, 512: 2.3, 544: 2.3, 612: 2.1, 629: 1.54, 665: 1, 813: 2.6, 854: 2.27, 894: 1.93, 896: 2.1, 937: 2.05, 938: 2.06, 981: 1.62, 1258: 2.68, 1309: 2.33, 1484: 1, 1763: 2.14, 1823: 2.48, 1882: 2.1, 1944: 1.72, 2380: 2.34, 3367: 2.44, 3733: 2.11, 3819: 2.6, 3821: 2.36, 4736: 2.75, 5724: 2.73, 5959: 2.63, 6519: 2.84, 6750: 2.87, 8991: 2.81 }; - -const __DefaultBondingRadius = 2.001; - -const MetalsSet = (function () { - const metals = ['LI', 'NA', 'K', 'RB', 'CS', 'FR', 'BE', 'MG', 'CA', 'SR', 'BA', 'RA', 'AL', 'GA', 'IN', 'SN', 'TL', 'PB', 'BI', 'SC', 'TI', 'V', 'CR', 'MN', 'FE', 'CO', 'NI', 'CU', 'ZN', 'Y', 'ZR', 'NB', 'MO', 'TC', 'RU', 'RH', 'PD', 'AG', 'CD', 'LA', 'HF', 'TA', 'W', 'RE', 'OS', 'IR', 'PT', 'AU', 'HG', 'AC', 'RF', 'DB', 'SG', 'BH', 'HS', 'MT', 'CE', 'PR', 'ND', 'PM', 'SM', 'EU', 'GD', 'TB', 'DY', 'HO', 'ER', 'TM', 'YB', 'LU', 'TH', 'PA', 'U', 'NP', 'PU', 'AM', 'CM', 'BK', 'CF', 'ES', 'FM', 'MD', 'NO', 'LR']; - const set = new Set<number>(); - for (const m of metals) { - set.add(__ElementIndex[m]!); - } - return set; -})(); - -function pair(a: number, b: number) { - if (a < b) return (a + b) * (a + b + 1) / 2 + b; - else return (a + b) * (a + b + 1) / 2 + a; -} - -function idx(e: ElementSymbol) { - const i = __ElementIndex[e as any as string]; - if (i === void 0) return -1; - return i; -} - -function pairThreshold(i: number, j: number) { - if (i < 0 || j < 0) return -1; - const r = __ElementPairThresholds[pair(i, j)]; - if (r === void 0) return -1; - return r; -} - -function threshold(i: number) { - if (i < 0) return __DefaultBondingRadius; - const r = __ElementBondThresholds[i]; - if (r === void 0) return __DefaultBondingRadius; - return r; -} - -const H_ID = __ElementIndex['H']!; -function isHydrogen(i: number) { - return i === H_ID; -} - -function getGraph(atomA: number[], atomB: number[], _order: number[], _flags: number[], atomCount: number): IntraUnitBonds { - const builder = new IntGraph.EdgeBuilder(atomCount, atomA, atomB); - const flags = new Uint16Array(builder.slotCount); - const order = new Int8Array(builder.slotCount); - for (let i = 0, _i = builder.edgeCount; i < _i; i++) { - builder.addNextEdge(); - builder.assignProperty(flags, _flags[i]); - builder.assignProperty(order, _order[i]); - } - - return builder.createGraph({ flags, order }); -} - -function _computeBonds(unit: Unit.Atomic, params: BondComputationParameters): IntraUnitBonds { - const MAX_RADIUS = 3; - - const { x, y, z } = unit.model.atomicConformation; - const atomCount = unit.elements.length; - const { elements: atoms, residueIndex } = unit; - const { type_symbol, label_atom_id, label_alt_id } = unit.model.atomicHierarchy.atoms; - const { label_comp_id } = unit.model.atomicHierarchy.residues; - const query3d = unit.lookup3d; - - const structConn = unit.model.sourceData.kind === 'mmCIF' ? StructConn.create(unit.model) : void 0 - const component = unit.model.sourceData.kind === 'mmCIF' ? ComponentBondInfo.create(unit.model) : void 0 - - const atomA: number[] = []; - const atomB: number[] = []; - const flags: number[] = []; - const order: number[] = []; - - let lastResidue = -1; - let componentMap: Map<string, Map<string, { flags: number, order: number }>> | undefined = void 0; - - for (let _aI = 0; _aI < atomCount; _aI++) { - const aI = atoms[_aI]; - const raI = residueIndex[aI]; - - if (!params.forceCompute && raI !== lastResidue) { - const resn = label_comp_id.value(raI)!; - if (!!component && component.entries.has(resn)) { - componentMap = component.entries.get(resn)!.map; - } else { - componentMap = void 0; - } - } - lastResidue = raI; - - const componentPairs = componentMap ? componentMap.get(label_atom_id.value(aI)) : void 0; - - const aeI = idx(type_symbol.value(aI)!); - - const { indices, count, squaredDistances } = query3d.find(x[aI], y[aI], z[aI], MAX_RADIUS); - const isHa = isHydrogen(aeI); - const thresholdA = threshold(aeI); - const altA = label_alt_id.value(aI); - const metalA = MetalsSet.has(aeI); - const structConnEntries = params.forceCompute ? void 0 : structConn && structConn.getAtomEntries(aI); - - for (let ni = 0; ni < count; ni++) { - const _bI = indices[ni]; - const bI = atoms[_bI]; - if (bI <= aI) continue; - - const altB = label_alt_id.value(bI); - if (altA && altB && altA !== altB) continue; - - const beI = idx(type_symbol.value(bI)!); - const isMetal = metalA || MetalsSet.has(beI); - - const rbI = residueIndex[bI]; - // handle "component dictionary" bonds. - if (raI === rbI && componentPairs) { - const e = componentPairs.get(label_atom_id.value(bI)!); - if (e) { - atomA[atomA.length] = _aI; - atomB[atomB.length] = _bI; - order[order.length] = e.order; - let flag = e.flags; - if (isMetal) { - if (flag | BondType.Flag.Covalent) flag ^= BondType.Flag.Covalent; - flag |= BondType.Flag.MetallicCoordination; - } - flags[flags.length] = flag; - } - continue; - } - - const isHb = isHydrogen(beI); - if (isHa && isHb) continue; - - const dist = Math.sqrt(squaredDistances[ni]); - if (dist === 0) continue; - - // handle "struct conn" bonds. - if (structConnEntries && structConnEntries.length) { - let added = false; - for (const se of structConnEntries) { - for (const p of se.partners) { - if (p.atomIndex === bI) { - atomA[atomA.length] = _aI; - atomB[atomB.length] = _bI; - flags[flags.length] = se.flags; - order[order.length] = se.order; - added = true; - break; - } - } - if (added) break; - } - if (added) continue; - } - - if (isHa || isHb) { - if (dist < params.maxHbondLength) { - atomA[atomA.length] = _aI; - atomB[atomB.length] = _bI; - order[order.length] = 1; - flags[flags.length] = BondType.Flag.Covalent | BondType.Flag.Computed; // TODO: check if correct - } - continue; - } - - const thresholdAB = pairThreshold(aeI, beI); - const pairingThreshold = thresholdAB > 0 - ? thresholdAB - : beI < 0 ? thresholdA : Math.max(thresholdA, threshold(beI)); - - - if (dist <= pairingThreshold) { - atomA[atomA.length] = _aI; - atomB[atomB.length] = _bI; - order[order.length] = 1; - flags[flags.length] = (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed; - } - } - } - - return getGraph(atomA, atomB, order, flags, atomCount); -} - -function computeIntraUnitBonds(unit: Unit.Atomic, params?: Partial<BondComputationParameters>) { - return _computeBonds(unit, { - maxHbondLength: (params && params.maxHbondLength) || 1.15, - forceCompute: !!(params && params.forceCompute), - }); -} - -export { computeIntraUnitBonds } \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/bonds/intra-data.ts b/src/mol-model/structure/structure/unit/bonds/intra-data.ts deleted file mode 100644 index 9914145379663e38ce3882ef4634bd57ae3da57e..0000000000000000000000000000000000000000 --- a/src/mol-model/structure/structure/unit/bonds/intra-data.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2017-2018 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 { BondType } from '../../../model/types' -import { IntGraph } from 'mol-math/graph'; - -type IntraUnitBonds = IntGraph<{ readonly order: ArrayLike<number>, readonly flags: ArrayLike<BondType.Flag> }> - -namespace IntraUnitBonds { - export function createEmpty(): IntraUnitBonds { - return IntGraph.create([], [], [], 0, { flags: [], order: [] }); - } - export function isCovalent(flags: number) { - return (flags & BondType.Flag.Covalent) !== 0; - } - export interface StructConnEntry { - flags: BondType.Flag, - order: number, - distance: number, - partners: { residueIndex: number, atomIndex: number, symmetry: string }[] - } - export interface StructConn { - getResidueEntries(residueAIndex: number, residueBIndex: number): ReadonlyArray<StructConnEntry> - getAtomEntries(atomIndex: number): ReadonlyArray<StructConnEntry> - } - export interface ComponentBondInfoEntry { - map: Map<string, Map<string, { order: number, flags: number }>> - } - export interface ComponentBondInfo { - entries: Map<string, ComponentBondInfoEntry> - } -} - -export { IntraUnitBonds } \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/bonds.ts b/src/mol-model/structure/structure/unit/links.ts similarity index 58% rename from src/mol-model/structure/structure/unit/bonds.ts rename to src/mol-model/structure/structure/unit/links.ts index d7268742832c8d7ff04d19199e218655ff48a099..20345c1bfd56e36caa39d01afe9d72ec38bc0aec 100644 --- a/src/mol-model/structure/structure/unit/bonds.ts +++ b/src/mol-model/structure/structure/unit/links.ts @@ -6,10 +6,11 @@ import { Unit } from '../../structure' -export * from './bonds/intra-data' -export * from './bonds/intra-compute' +export * from './links/data' +export * from './links/intra-compute' +export * from './links/inter-compute' -namespace Bond { +namespace Link { export interface Location { readonly aUnit: Unit, /** Index into aUnit.elements */ @@ -20,17 +21,17 @@ namespace Bond { } export interface Loci { - readonly kind: 'bond-loci', - readonly bonds: ReadonlyArray<Location> + readonly kind: 'link-loci', + readonly links: ReadonlyArray<Location> } - export function Loci(bonds: ArrayLike<Location>): Loci { - return { kind: 'bond-loci', bonds: bonds as Loci['bonds'] }; + export function Loci(links: ArrayLike<Location>): Loci { + return { kind: 'link-loci', links: links as Loci['links'] }; } export function isLoci(x: any): x is Loci { - return !!x && x.kind === 'bond-loci'; + return !!x && x.kind === 'link-loci'; } } -export { Bond } \ No newline at end of file +export { Link } \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/links/common.ts b/src/mol-model/structure/structure/unit/links/common.ts new file mode 100644 index 0000000000000000000000000000000000000000..6457c86b89ae8bbfd20a33894dc118f271076b6d --- /dev/null +++ b/src/mol-model/structure/structure/unit/links/common.ts @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2017-2018 Mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { ElementSymbol } from '../../../model/types'; + +export interface LinkComputationParameters { + maxHbondLength: number, + forceCompute: boolean +} + +// H,D,T are all mapped to H +const __ElementIndex: { [e: string]: number | undefined } = { 'H': 0, 'h': 0, 'D': 0, 'd': 0, 'T': 0, 't': 0, 'He': 2, 'HE': 2, 'he': 2, 'Li': 3, 'LI': 3, 'li': 3, 'Be': 4, 'BE': 4, 'be': 4, 'B': 5, 'b': 5, 'C': 6, 'c': 6, 'N': 7, 'n': 7, 'O': 8, 'o': 8, 'F': 9, 'f': 9, 'Ne': 10, 'NE': 10, 'ne': 10, 'Na': 11, 'NA': 11, 'na': 11, 'Mg': 12, 'MG': 12, 'mg': 12, 'Al': 13, 'AL': 13, 'al': 13, 'Si': 14, 'SI': 14, 'si': 14, 'P': 15, 'p': 15, 'S': 16, 's': 16, 'Cl': 17, 'CL': 17, 'cl': 17, 'Ar': 18, 'AR': 18, 'ar': 18, 'K': 19, 'k': 19, 'Ca': 20, 'CA': 20, 'ca': 20, 'Sc': 21, 'SC': 21, 'sc': 21, 'Ti': 22, 'TI': 22, 'ti': 22, 'V': 23, 'v': 23, 'Cr': 24, 'CR': 24, 'cr': 24, 'Mn': 25, 'MN': 25, 'mn': 25, 'Fe': 26, 'FE': 26, 'fe': 26, 'Co': 27, 'CO': 27, 'co': 27, 'Ni': 28, 'NI': 28, 'ni': 28, 'Cu': 29, 'CU': 29, 'cu': 29, 'Zn': 30, 'ZN': 30, 'zn': 30, 'Ga': 31, 'GA': 31, 'ga': 31, 'Ge': 32, 'GE': 32, 'ge': 32, 'As': 33, 'AS': 33, 'as': 33, 'Se': 34, 'SE': 34, 'se': 34, 'Br': 35, 'BR': 35, 'br': 35, 'Kr': 36, 'KR': 36, 'kr': 36, 'Rb': 37, 'RB': 37, 'rb': 37, 'Sr': 38, 'SR': 38, 'sr': 38, 'Y': 39, 'y': 39, 'Zr': 40, 'ZR': 40, 'zr': 40, 'Nb': 41, 'NB': 41, 'nb': 41, 'Mo': 42, 'MO': 42, 'mo': 42, 'Tc': 43, 'TC': 43, 'tc': 43, 'Ru': 44, 'RU': 44, 'ru': 44, 'Rh': 45, 'RH': 45, 'rh': 45, 'Pd': 46, 'PD': 46, 'pd': 46, 'Ag': 47, 'AG': 47, 'ag': 47, 'Cd': 48, 'CD': 48, 'cd': 48, 'In': 49, 'IN': 49, 'in': 49, 'Sn': 50, 'SN': 50, 'sn': 50, 'Sb': 51, 'SB': 51, 'sb': 51, 'Te': 52, 'TE': 52, 'te': 52, 'I': 53, 'i': 53, 'Xe': 54, 'XE': 54, 'xe': 54, 'Cs': 55, 'CS': 55, 'cs': 55, 'Ba': 56, 'BA': 56, 'ba': 56, 'La': 57, 'LA': 57, 'la': 57, 'Ce': 58, 'CE': 58, 'ce': 58, 'Pr': 59, 'PR': 59, 'pr': 59, 'Nd': 60, 'ND': 60, 'nd': 60, 'Pm': 61, 'PM': 61, 'pm': 61, 'Sm': 62, 'SM': 62, 'sm': 62, 'Eu': 63, 'EU': 63, 'eu': 63, 'Gd': 64, 'GD': 64, 'gd': 64, 'Tb': 65, 'TB': 65, 'tb': 65, 'Dy': 66, 'DY': 66, 'dy': 66, 'Ho': 67, 'HO': 67, 'ho': 67, 'Er': 68, 'ER': 68, 'er': 68, 'Tm': 69, 'TM': 69, 'tm': 69, 'Yb': 70, 'YB': 70, 'yb': 70, 'Lu': 71, 'LU': 71, 'lu': 71, 'Hf': 72, 'HF': 72, 'hf': 72, 'Ta': 73, 'TA': 73, 'ta': 73, 'W': 74, 'w': 74, 'Re': 75, 'RE': 75, 're': 75, 'Os': 76, 'OS': 76, 'os': 76, 'Ir': 77, 'IR': 77, 'ir': 77, 'Pt': 78, 'PT': 78, 'pt': 78, 'Au': 79, 'AU': 79, 'au': 79, 'Hg': 80, 'HG': 80, 'hg': 80, 'Tl': 81, 'TL': 81, 'tl': 81, 'Pb': 82, 'PB': 82, 'pb': 82, 'Bi': 83, 'BI': 83, 'bi': 83, 'Po': 84, 'PO': 84, 'po': 84, 'At': 85, 'AT': 85, 'at': 85, 'Rn': 86, 'RN': 86, 'rn': 86, 'Fr': 87, 'FR': 87, 'fr': 87, 'Ra': 88, 'RA': 88, 'ra': 88, 'Ac': 89, 'AC': 89, 'ac': 89, 'Th': 90, 'TH': 90, 'th': 90, 'Pa': 91, 'PA': 91, 'pa': 91, 'U': 92, 'u': 92, 'Np': 93, 'NP': 93, 'np': 93, 'Pu': 94, 'PU': 94, 'pu': 94, 'Am': 95, 'AM': 95, 'am': 95, 'Cm': 96, 'CM': 96, 'cm': 96, 'Bk': 97, 'BK': 97, 'bk': 97, 'Cf': 98, 'CF': 98, 'cf': 98, 'Es': 99, 'ES': 99, 'es': 99, 'Fm': 100, 'FM': 100, 'fm': 100, 'Md': 101, 'MD': 101, 'md': 101, 'No': 102, 'NO': 102, 'no': 102, 'Lr': 103, 'LR': 103, 'lr': 103, 'Rf': 104, 'RF': 104, 'rf': 104, 'Db': 105, 'DB': 105, 'db': 105, 'Sg': 106, 'SG': 106, 'sg': 106, 'Bh': 107, 'BH': 107, 'bh': 107, 'Hs': 108, 'HS': 108, 'hs': 108, 'Mt': 109, 'MT': 109, 'mt': 109 }; + +const __ElementBondThresholds: { [e: number]: number | undefined } = { 0: 1.42, 1: 1.42, 3: 2.7, 4: 2.7, 6: 1.75, 7: 1.6, 8: 1.52, 11: 2.7, 12: 2.7, 13: 2.7, 14: 1.9, 15: 1.9, 16: 1.9, 17: 1.8, 19: 2.7, 20: 2.7, 21: 2.7, 22: 2.7, 23: 2.7, 24: 2.7, 25: 2.7, 26: 2.7, 27: 2.7, 28: 2.7, 29: 2.7, 30: 2.7, 31: 2.7, 33: 2.68, 37: 2.7, 38: 2.7, 39: 2.7, 40: 2.7, 41: 2.7, 42: 2.7, 43: 2.7, 44: 2.7, 45: 2.7, 46: 2.7, 47: 2.7, 48: 2.7, 49: 2.7, 50: 2.7, 55: 2.7, 56: 2.7, 57: 2.7, 58: 2.7, 59: 2.7, 60: 2.7, 61: 2.7, 62: 2.7, 63: 2.7, 64: 2.7, 65: 2.7, 66: 2.7, 67: 2.7, 68: 2.7, 69: 2.7, 70: 2.7, 71: 2.7, 72: 2.7, 73: 2.7, 74: 2.7, 75: 2.7, 76: 2.7, 77: 2.7, 78: 2.7, 79: 2.7, 80: 2.7, 81: 2.7, 82: 2.7, 83: 2.7, 87: 2.7, 88: 2.7, 89: 2.7, 90: 2.7, 91: 2.7, 92: 2.7, 93: 2.7, 94: 2.7, 95: 2.7, 96: 2.7, 97: 2.7, 98: 2.7, 99: 2.7, 100: 2.7, 101: 2.7, 102: 2.7, 103: 2.7, 104: 2.7, 105: 2.7, 106: 2.7, 107: 2.7, 108: 2.7, 109: 2.88 }; + +const __ElementPairThresholds: { [e: number]: number | undefined } = { 0: 0.8, 20: 1.31, 27: 1.3, 35: 1.3, 44: 1.05, 54: 1, 60: 1.84, 72: 1.88, 84: 1.75, 85: 1.56, 86: 1.76, 98: 1.6, 99: 1.68, 100: 1.63, 112: 1.55, 113: 1.59, 114: 1.36, 129: 1.45, 144: 1.6, 170: 1.4, 180: 1.55, 202: 2.4, 222: 2.24, 224: 1.91, 225: 1.98, 243: 2.02, 269: 2, 293: 1.9, 480: 2.3, 512: 2.3, 544: 2.3, 612: 2.1, 629: 1.54, 665: 1, 813: 2.6, 854: 2.27, 894: 1.93, 896: 2.1, 937: 2.05, 938: 2.06, 981: 1.62, 1258: 2.68, 1309: 2.33, 1484: 1, 1763: 2.14, 1823: 2.48, 1882: 2.1, 1944: 1.72, 2380: 2.34, 3367: 2.44, 3733: 2.11, 3819: 2.6, 3821: 2.36, 4736: 2.75, 5724: 2.73, 5959: 2.63, 6519: 2.84, 6750: 2.87, 8991: 2.81 }; + +const __DefaultBondingRadius = 2.001; + +export const MetalsSet = (function () { + const metals = ['LI', 'NA', 'K', 'RB', 'CS', 'FR', 'BE', 'MG', 'CA', 'SR', 'BA', 'RA', 'AL', 'GA', 'IN', 'SN', 'TL', 'PB', 'BI', 'SC', 'TI', 'V', 'CR', 'MN', 'FE', 'CO', 'NI', 'CU', 'ZN', 'Y', 'ZR', 'NB', 'MO', 'TC', 'RU', 'RH', 'PD', 'AG', 'CD', 'LA', 'HF', 'TA', 'W', 'RE', 'OS', 'IR', 'PT', 'AU', 'HG', 'AC', 'RF', 'DB', 'SG', 'BH', 'HS', 'MT', 'CE', 'PR', 'ND', 'PM', 'SM', 'EU', 'GD', 'TB', 'DY', 'HO', 'ER', 'TM', 'YB', 'LU', 'TH', 'PA', 'U', 'NP', 'PU', 'AM', 'CM', 'BK', 'CF', 'ES', 'FM', 'MD', 'NO', 'LR']; + const set = new Set<number>(); + for (const m of metals) { + set.add(__ElementIndex[m]!); + } + return set; +})(); + +function pair(a: number, b: number) { + if (a < b) return (a + b) * (a + b + 1) / 2 + b; + else return (a + b) * (a + b + 1) / 2 + a; +} + +export function getElementIdx(e: ElementSymbol) { + const i = __ElementIndex[e as any as string]; + if (i === void 0) return -1; + return i; +} + +export function getElementPairThreshold(i: number, j: number) { + if (i < 0 || j < 0) return -1; + const r = __ElementPairThresholds[pair(i, j)]; + if (r === void 0) return -1; + return r; +} + +export function getElementThreshold(i: number) { + if (i < 0) return __DefaultBondingRadius; + const r = __ElementBondThresholds[i]; + if (r === void 0) return __DefaultBondingRadius; + return r; +} + +const H_ID = __ElementIndex['H']!; +export function isHydrogen(i: number) { + return i === H_ID; +} \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/links/data.ts b/src/mol-model/structure/structure/unit/links/data.ts new file mode 100644 index 0000000000000000000000000000000000000000..dfd9762c5a6fdc0578f94f56011bcd8605d7cbc0 --- /dev/null +++ b/src/mol-model/structure/structure/unit/links/data.ts @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2017-2018 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 { LinkType } from '../../../model/types' +import { IntAdjacencyGraph } from 'mol-math/graph'; +import Unit from '../../unit'; + +type IntraUnitLinks = IntAdjacencyGraph<{ readonly order: ArrayLike<number>, readonly flags: ArrayLike<LinkType.Flag> }> + +namespace IntraUnitLinks { + export const Empty: IntraUnitLinks = IntAdjacencyGraph.create([], [], [], 0, { flags: [], order: [] }); +} + +class InterUnitBonds { + getLinkedUnits(unit: Unit): ReadonlyArray<InterUnitBonds.UnitPairBonds> { + if (!this.map.has(unit.id)) return emptyArray; + return this.map.get(unit.id)!; + } + + constructor(private map: Map<number, InterUnitBonds.UnitPairBonds[]>) { + } +} + +namespace InterUnitBonds { + export class UnitPairBonds { + hasBonds(indexA: number) { + return this.linkMap.has(indexA); + } + + getBonds(indexA: number): ReadonlyArray<InterUnitBonds.BondInfo> { + if (!this.linkMap.has(indexA)) return emptyArray; + return this.linkMap.get(indexA)!; + } + + get areUnitsOrdered() { + return this.unitA.id < this.unitB.id; + } + + constructor(public unitA: Unit.Atomic, public unitB: Unit.Atomic, + public bondCount: number, public linkedElementIndices: ReadonlyArray<number>, + private linkMap: Map<number, BondInfo[]>) { + } + } + + export interface BondInfo { + /** indexInto */ + readonly indexB: number, + readonly order: number, + readonly flag: LinkType.Flag + } +} + +const emptyArray: any[] = []; + +export { IntraUnitLinks, InterUnitBonds } \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/links/inter-compute.ts b/src/mol-model/structure/structure/unit/links/inter-compute.ts new file mode 100644 index 0000000000000000000000000000000000000000..abb607102bf62788d4652fd7440737c1b91b6d85 --- /dev/null +++ b/src/mol-model/structure/structure/unit/links/inter-compute.ts @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2017 Mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { StructConn } from '../../../model/formats/mmcif/bonds'; +import { LinkType } from '../../../model/types'; +import Structure from '../../structure'; +import Unit from '../../unit'; +import { getElementIdx, getElementPairThreshold, getElementThreshold, isHydrogen, LinkComputationParameters, MetalsSet } from './common'; +import { InterUnitBonds } from './data'; +import { UniqueArray } from 'mol-data/generic'; + +const MAX_RADIUS = 4; + +function addMapEntry<A, B>(map: Map<A, B[]>, a: A, b: B) { + if (map.has(a)) map.get(a)!.push(b); + else map.set(a, [b]); +} + +interface PairState { + mapAB: Map<number, InterUnitBonds.BondInfo[]>, + mapBA: Map<number, InterUnitBonds.BondInfo[]>, + bondedA: UniqueArray<number, number>, + bondedB: UniqueArray<number, number> +} + +function addLink(indexA: number, indexB: number, order: number, flag: LinkType.Flag, state: PairState) { + addMapEntry(state.mapAB, indexA, { indexB, order, flag }); + addMapEntry(state.mapBA, indexB, { indexB: indexA, order, flag }); + UniqueArray.add(state.bondedA, indexA, indexA); + UniqueArray.add(state.bondedB, indexB, indexB); +} + +function findPairLinks(unitA: Unit.Atomic, unitB: Unit.Atomic, params: LinkComputationParameters, map: Map<number, InterUnitBonds.UnitPairBonds[]>) { + const state: PairState = { mapAB: new Map(), mapBA: new Map(), bondedA: UniqueArray.create(), bondedB: UniqueArray.create() }; + let bondCount = 0; + + const { elements: atomsA, conformation: { x, y, z } } = unitA; + const { elements: atomsB } = unitB; + const atomCount = unitA.elements.length; + + const { type_symbol: type_symbolA, label_alt_id: label_alt_idA } = unitA.model.atomicHierarchy.atoms; + const { type_symbol: type_symbolB, label_alt_id: label_alt_idB } = unitB.model.atomicHierarchy.atoms; + const { lookup3d } = unitB; + const structConn = unitA.model === unitB.model && unitA.model.sourceData.kind === 'mmCIF' ? StructConn.create(unitA.model) : void 0; + + for (let _aI = 0; _aI < atomCount; _aI++) { + const aI = atomsA[_aI]; + + const aeI = getElementIdx(type_symbolA.value(aI)); + const { indices, count, squaredDistances } = lookup3d.find(x(aI), y(aI), z(aI), MAX_RADIUS); + const isHa = isHydrogen(aeI); + const thresholdA = getElementThreshold(aeI); + const altA = label_alt_idA.value(aI); + const metalA = MetalsSet.has(aeI); + const structConnEntries = params.forceCompute ? void 0 : structConn && structConn.getAtomEntries(aI); + + for (let ni = 0; ni < count; ni++) { + const _bI = indices[ni]; + const bI = atomsB[_bI]; + + const altB = label_alt_idB.value(bI); + // TODO: check if they have the same model? + if (altA && altB && altA !== altB) continue; + + const beI = getElementIdx(type_symbolB.value(bI)!); + const isMetal = metalA || MetalsSet.has(beI); + + const isHb = isHydrogen(beI); + if (isHa && isHb) continue; + + const dist = Math.sqrt(squaredDistances[ni]); + if (dist === 0) continue; + + // handle "struct conn" bonds. + if (structConnEntries && structConnEntries.length) { + let added = false; + for (const se of structConnEntries) { + for (const p of se.partners) { + if (p.atomIndex === bI) { + addLink(_aI, _bI, se.order, se.flags, state); + bondCount++; + added = true; + break; + } + } + if (added) break; + } + if (added) continue; + } + + if (isHa || isHb) { + if (dist < params.maxHbondLength) { + addLink(_aI, _bI, 1, LinkType.Flag.Covalent | LinkType.Flag.Computed, state); // TODO: check if correct + bondCount++; + } + continue; + } + + const thresholdAB = getElementPairThreshold(aeI, beI); + const pairingThreshold = thresholdAB > 0 + ? thresholdAB + : beI < 0 ? thresholdA : Math.max(thresholdA, getElementThreshold(beI)); + + if (dist <= pairingThreshold) { + addLink(_aI, _bI, 1, (isMetal ? LinkType.Flag.MetallicCoordination : LinkType.Flag.Covalent) | LinkType.Flag.Computed, state); + bondCount++; + } + } + } + + addMapEntry(map, unitA.id, new InterUnitBonds.UnitPairBonds(unitA, unitB, bondCount, state.bondedA.array, state.mapAB)); + addMapEntry(map, unitB.id, new InterUnitBonds.UnitPairBonds(unitB, unitA, bondCount, state.bondedB.array, state.mapBA)); + + return bondCount; +} + +function findLinks(structure: Structure, params: LinkComputationParameters) { + const map = new Map<number, InterUnitBonds.UnitPairBonds[]>(); + if (!structure.units.some(u => Unit.isAtomic(u))) return new InterUnitBonds(map); + + const lookup = structure.lookup3d; + for (const unit of structure.units) { + if (!Unit.isAtomic(unit)) continue; + + const bs = unit.lookup3d.boundary.sphere; + const closeUnits = lookup.findUnitIndices(bs.center[0], bs.center[1], bs.center[2], bs.radius + MAX_RADIUS); + for (let i = 0; i < closeUnits.count; i++) { + const other = structure.units[closeUnits.indices[i]]; + if (!Unit.isAtomic(other) || unit.id >= other.id) continue; + + if (other.elements.length >= unit.elements.length) findPairLinks(unit, other, params, map); + else findPairLinks(other, unit, params, map); + } + } + + return new InterUnitBonds(map); +} + +function computeInterUnitBonds(structure: Structure, params?: Partial<LinkComputationParameters>): InterUnitBonds { + return findLinks(structure, { + maxHbondLength: (params && params.maxHbondLength) || 1.15, + forceCompute: !!(params && params.forceCompute), + }); +} + +export { computeInterUnitBonds }; diff --git a/src/mol-model/structure/structure/unit/links/intra-compute.ts b/src/mol-model/structure/structure/unit/links/intra-compute.ts new file mode 100644 index 0000000000000000000000000000000000000000..43a67a8ac5d9282a5c978658f845e47f04320e48 --- /dev/null +++ b/src/mol-model/structure/structure/unit/links/intra-compute.ts @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2017 Mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { LinkType } from '../../../model/types' +import { IntraUnitLinks } from './data' +import { StructConn, ComponentBondInfo } from '../../../model/formats/mmcif/bonds' +import Unit from '../../unit' +import { IntAdjacencyGraph } from 'mol-math/graph'; +import { LinkComputationParameters, getElementIdx, MetalsSet, getElementThreshold, isHydrogen, getElementPairThreshold } from './common'; + +function getGraph(atomA: number[], atomB: number[], _order: number[], _flags: number[], atomCount: number): IntraUnitLinks { + const builder = new IntAdjacencyGraph.EdgeBuilder(atomCount, atomA, atomB); + const flags = new Uint16Array(builder.slotCount); + const order = new Int8Array(builder.slotCount); + for (let i = 0, _i = builder.edgeCount; i < _i; i++) { + builder.addNextEdge(); + builder.assignProperty(flags, _flags[i]); + builder.assignProperty(order, _order[i]); + } + + return builder.createGraph({ flags, order }); +} + +function _computeBonds(unit: Unit.Atomic, params: LinkComputationParameters): IntraUnitLinks { + const MAX_RADIUS = 4; + + const { x, y, z } = unit.model.atomicConformation; + const atomCount = unit.elements.length; + const { elements: atoms, residueIndex } = unit; + const { type_symbol, label_atom_id, label_alt_id } = unit.model.atomicHierarchy.atoms; + const { label_comp_id } = unit.model.atomicHierarchy.residues; + const query3d = unit.lookup3d; + + const structConn = unit.model.sourceData.kind === 'mmCIF' ? StructConn.create(unit.model) : void 0; + const component = unit.model.sourceData.kind === 'mmCIF' ? ComponentBondInfo.create(unit.model) : void 0; + + const atomA: number[] = []; + const atomB: number[] = []; + const flags: number[] = []; + const order: number[] = []; + + let lastResidue = -1; + let componentMap: Map<string, Map<string, { flags: number, order: number }>> | undefined = void 0; + + for (let _aI = 0; _aI < atomCount; _aI++) { + const aI = atoms[_aI]; + const raI = residueIndex[aI]; + + if (!params.forceCompute && raI !== lastResidue) { + const resn = label_comp_id.value(raI)!; + if (!!component && component.entries.has(resn)) { + componentMap = component.entries.get(resn)!.map; + } else { + componentMap = void 0; + } + } + lastResidue = raI; + + const componentPairs = componentMap ? componentMap.get(label_atom_id.value(aI)) : void 0; + + const aeI = getElementIdx(type_symbol.value(aI)!); + + const { indices, count, squaredDistances } = query3d.find(x[aI], y[aI], z[aI], MAX_RADIUS); + const isHa = isHydrogen(aeI); + const thresholdA = getElementThreshold(aeI); + const altA = label_alt_id.value(aI); + const metalA = MetalsSet.has(aeI); + const structConnEntries = params.forceCompute ? void 0 : structConn && structConn.getAtomEntries(aI); + + for (let ni = 0; ni < count; ni++) { + const _bI = indices[ni]; + const bI = atoms[_bI]; + if (bI <= aI) continue; + + const altB = label_alt_id.value(bI); + if (altA && altB && altA !== altB) continue; + + const beI = getElementIdx(type_symbol.value(bI)!); + const isMetal = metalA || MetalsSet.has(beI); + + const rbI = residueIndex[bI]; + // handle "component dictionary" bonds. + if (raI === rbI && componentPairs) { + const e = componentPairs.get(label_atom_id.value(bI)!); + if (e) { + atomA[atomA.length] = _aI; + atomB[atomB.length] = _bI; + order[order.length] = e.order; + let flag = e.flags; + if (isMetal) { + if (flag | LinkType.Flag.Covalent) flag ^= LinkType.Flag.Covalent; + flag |= LinkType.Flag.MetallicCoordination; + } + flags[flags.length] = flag; + } + continue; + } + + const isHb = isHydrogen(beI); + if (isHa && isHb) continue; + + const dist = Math.sqrt(squaredDistances[ni]); + if (dist === 0) continue; + + // handle "struct conn" bonds. + if (structConnEntries && structConnEntries.length) { + let added = false; + for (const se of structConnEntries) { + for (const p of se.partners) { + if (p.atomIndex === bI) { + atomA[atomA.length] = _aI; + atomB[atomB.length] = _bI; + flags[flags.length] = se.flags; + order[order.length] = se.order; + added = true; + break; + } + } + if (added) break; + } + if (added) continue; + } + + if (isHa || isHb) { + if (dist < params.maxHbondLength) { + atomA[atomA.length] = _aI; + atomB[atomB.length] = _bI; + order[order.length] = 1; + flags[flags.length] = LinkType.Flag.Covalent | LinkType.Flag.Computed; // TODO: check if correct + } + continue; + } + + const thresholdAB = getElementPairThreshold(aeI, beI); + const pairingThreshold = thresholdAB > 0 + ? thresholdAB + : beI < 0 ? thresholdA : Math.max(thresholdA, getElementThreshold(beI)); + + if (dist <= pairingThreshold) { + atomA[atomA.length] = _aI; + atomB[atomB.length] = _bI; + order[order.length] = 1; + flags[flags.length] = (isMetal ? LinkType.Flag.MetallicCoordination : LinkType.Flag.Covalent) | LinkType.Flag.Computed; + } + } + } + + return getGraph(atomA, atomB, order, flags, atomCount); +} + +function computeIntraUnitBonds(unit: Unit.Atomic, params?: Partial<LinkComputationParameters>) { + return _computeBonds(unit, { + maxHbondLength: (params && params.maxHbondLength) || 1.15, + forceCompute: !!(params && params.forceCompute), + }); +} + +export { computeIntraUnitBonds } \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/rings/compute.ts b/src/mol-model/structure/structure/unit/rings/compute.ts index 3a83594121a8150912f1a6daabba7278767008e2..c0bafe3e3abe380d3557ef14edfdd3225299902b 100644 --- a/src/mol-model/structure/structure/unit/rings/compute.ts +++ b/src/mol-model/structure/structure/unit/rings/compute.ts @@ -5,8 +5,9 @@ */ import Unit from '../../unit'; -import { IntraUnitBonds } from '../bonds/intra-data'; +import { IntraUnitLinks } from '../links/data'; import { Segmentation } from 'mol-data/int'; +import { LinkType } from '../../../model/types'; export default function computeRings(unit: Unit.Atomic) { const size = largestResidue(unit); @@ -40,7 +41,7 @@ interface State { currentColor: number, rings: number[][], - bonds: IntraUnitBonds, + bonds: IntraUnitLinks, unit: Unit.Atomic } @@ -58,7 +59,7 @@ function State(unit: Unit.Atomic, capacity: number): State { currentColor: 0, rings: [], unit, - bonds: unit.bonds + bonds: unit.links }; } @@ -160,7 +161,7 @@ function findRings(state: State, from: number) { for (let i = start; i < end; i++) { const b = neighbor[i]; - if (b < startVertex || b >= endVertex || !IntraUnitBonds.isCovalent(bondFlags[i])) continue; + if (b < startVertex || b >= endVertex || !LinkType.isCovalent(bondFlags[i])) continue; const other = b - startVertex; diff --git a/src/mol-model/structure/structure/util/lookup3d.ts b/src/mol-model/structure/structure/util/lookup3d.ts index 2ea308e3ec11624d1528fa28d8d9f38e49f96fd0..3c7b8b6ac24690292f4eacc144fde5fbf27368e8 100644 --- a/src/mol-model/structure/structure/util/lookup3d.ts +++ b/src/mol-model/structure/structure/util/lookup3d.ts @@ -17,6 +17,10 @@ export class StructureLookup3D implements Lookup3D<Element> { private result = Result.create<Element>(); private pivot = Vec3.zero(); + findUnitIndices(x: number, y: number, z: number, radius: number): Result<number> { + return this.unitLookup.find(x, y, z, radius); + } + find(x: number, y: number, z: number, radius: number): Result<Element> { Result.reset(this.result); const { units } = this.structure; diff --git a/src/mol-view/label.ts b/src/mol-view/label.ts index 578a4a7a53260c5c682edc6a7d648edf692a0031..0ea82df1ba0a07c339d76453580f942cf19a85cd 100644 --- a/src/mol-view/label.ts +++ b/src/mol-view/label.ts @@ -6,7 +6,7 @@ */ import { Unit, Element, Queries } from 'mol-model/structure'; -import { Bond } from 'mol-model/structure/structure/unit/bonds'; +import { Link } from 'mol-model/structure/structure/unit/links'; import { Loci } from 'mol-model/loci'; const elementLocA = Element.Location() @@ -23,8 +23,8 @@ export function labelFirst(loci: Loci) { if (e && e.indices[0] !== undefined) { return elementLabel(Element.Location(e.unit, e.indices[0])) } - } else if (Bond.isLoci(loci)) { - const bond = loci.bonds[0] + } else if (Link.isLoci(loci)) { + const bond = loci.links[0] if (bond) { setElementLocation(elementLocA, bond.aUnit, bond.aIndex) setElementLocation(elementLocB, bond.bUnit, bond.bIndex)