diff --git a/CHANGELOG.md b/CHANGELOG.md index a9bf194729db03f2118718ea4e2d54445edfc936..ce195bc72bfe53f3c7e1ca532f13527181771e00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Note that since we don't clearly distinguish between a public and private interf - [Fix] Clone ``Canvas3DParams`` when creating a ``Canvas3D`` instance to prevent shared state between multiple instances - Add ``includeResidueTest`` option to ``alignAndSuperposeWithSIFTSMapping`` - Add ``parentDisplay`` param for interactions representation. +- Add ``key`` property to intra- and inter-bonds for referencing source data ## [v3.16.0] - 2022-08-25 diff --git a/src/mol-model-formats/structure/property/bonds/chem_comp.ts b/src/mol-model-formats/structure/property/bonds/chem_comp.ts index b3f64adcff90adfd48410aa33035248c7f740ada..6ba2bc374891a16fff526ee3e8b7b96a3db37b70 100644 --- a/src/mol-model-formats/structure/property/bonds/chem_comp.ts +++ b/src/mol-model-formats/structure/property/bonds/chem_comp.ts @@ -65,7 +65,7 @@ export namespace ComponentBond { return e; } - const { comp_id, atom_id_1, atom_id_2, value_order, pdbx_aromatic_flag, _rowCount } = data; + const { comp_id, atom_id_1, atom_id_2, value_order, pdbx_aromatic_flag, _rowCount, pdbx_ordinal } = data; let entry = addEntry(comp_id.value(0)!); for (let i = 0; i < _rowCount; i++) { @@ -74,6 +74,7 @@ export namespace ComponentBond { const nameB = atom_id_2.value(i)!; const order = value_order.value(i)!; const aromatic = pdbx_aromatic_flag.value(i) === 'y'; + const key = pdbx_ordinal.value(i); if (entry.id !== id) { entry = addEntry(id); @@ -89,29 +90,29 @@ export namespace ComponentBond { case 'quad': ord = 4; break; } - entry.add(nameA, nameB, ord, flags); + entry.add(nameA, nameB, ord, flags, key); } return entries; } export class Entry { - readonly map: Map<string, Map<string, { order: number, flags: number }>> = new Map(); + readonly map: Map<string, Map<string, { order: number, flags: number, key: number }>> = new Map(); - add(a: string, b: string, order: number, flags: number, swap = true) { + add(a: string, b: string, order: number, flags: number, key: number, swap = true) { const e = this.map.get(a); if (e !== void 0) { const f = e.get(b); if (f === void 0) { - e.set(b, { order, flags }); + e.set(b, { order, flags, key }); } } else { - const map = new Map<string, { order: number, flags: number }>(); - map.set(b, { order, flags }); + const map = new Map<string, { order: number, flags: number, key: number }>(); + map.set(b, { order, flags, key }); this.map.set(a, map); } - if (swap) this.add(b, a, order, flags, false); + if (swap) this.add(b, a, order, flags, key, false); } constructor(public readonly id: string) { } diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts index 43b2538b98ba727032ab231948c203283e123f61..c51b441a77da6cfffd623877b0734df8e87fc757 100644 --- a/src/mol-model/structure/query/context.ts +++ b/src/mol-model/structure/query/context.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2018 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> */ import { Structure, StructureElement, Unit } from '../structure'; @@ -113,6 +114,7 @@ class QueryContextBondInfo<U extends Unit = Unit> { bIndex: StructureElement.UnitIndex = 0 as StructureElement.UnitIndex; type: BondType = BondType.Flag.None; order: number = 0; + key: number = -1; private testFn: QueryPredicate = defaultBondTest; diff --git a/src/mol-model/structure/query/queries/filters.ts b/src/mol-model/structure/query/queries/filters.ts index 128f9b4fa7d0b698d88a7f939140d5737c3f8e21..81e698f1649ada29eafa19194f1d2af23c5ab1a1 100644 --- a/src/mol-model/structure/query/queries/filters.ts +++ b/src/mol-model/structure/query/queries/filters.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2018 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> */ import { SetUtils } from '../../../../mol-util/set'; @@ -248,7 +249,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) { const inputUnit = input.unitMap.get(unit.id) as Unit.Atomic; - const { offset, b, edgeProps: { flags, order } } = inputUnit.bonds; + const { offset, b, edgeProps: { flags, order, key } } = inputUnit.bonds; const bondedUnits = interBonds.getConnectedUnits(unit.id); const buCount = bondedUnits.length; @@ -273,6 +274,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) { atomicBond.bIndex = b[l] as StructureElement.UnitIndex; atomicBond.type = flags[l]; atomicBond.order = order[l]; + atomicBond.key = key[l]; if (atomicBond.test(queryCtx, true)) return true; } @@ -295,6 +297,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) { atomicBond.bIndex = bond.indexB; atomicBond.type = bond.props.flag; atomicBond.order = bond.props.order; + atomicBond.key = bond.props.key; if (atomicBond.test(queryCtx, true)) return true; } } diff --git a/src/mol-model/structure/query/queries/generators.ts b/src/mol-model/structure/query/queries/generators.ts index e963dc2a5b2eb62f408ccde5f5bbfbf000c9510e..807114c5e2ccde81788992acb01c9719c19ec92e 100644 --- a/src/mol-model/structure/query/queries/generators.ts +++ b/src/mol-model/structure/query/queries/generators.ts @@ -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> @@ -322,7 +322,7 @@ export function bondedAtomicPairs(bondTest?: QueryPredicate): StructureQuery { for (const unit of structure.units) { if (unit.kind !== Unit.Kind.Atomic) continue; - const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order } } = unit.bonds; + const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order, key } } = unit.bonds; atomicBond.a.unit = unit; atomicBond.b.unit = unit; for (let i = 0 as StructureElement.UnitIndex, _i = unit.elements.length; i < _i; i++) { @@ -335,6 +335,7 @@ export function bondedAtomicPairs(bondTest?: QueryPredicate): StructureQuery { atomicBond.b.element = unit.elements[intraBondB[lI]]; atomicBond.type = flags[lI]; atomicBond.order = order[lI]; + atomicBond.key = key[lI]; // No need to "swap test" because each bond direction will be visited eventually. if (atomicBond.test(ctx, false)) { const b = structure.subsetBuilder(false); @@ -358,6 +359,7 @@ export function bondedAtomicPairs(bondTest?: QueryPredicate): StructureQuery { atomicBond.bIndex = bond.indexB; atomicBond.order = bond.props.order; atomicBond.type = bond.props.flag; + atomicBond.key = bond.props.key; // No need to "swap test" because each bond direction will be visited eventually. if (atomicBond.test(ctx, false)) { diff --git a/src/mol-model/structure/query/queries/modifiers.ts b/src/mol-model/structure/query/queries/modifiers.ts index c860695950b6b3430e8d6f8effa9843e4456b396..f10e9f7c7683243b6795c70e74c994d624678b5d 100644 --- a/src/mol-model/structure/query/queries/modifiers.ts +++ b/src/mol-model/structure/query/queries/modifiers.ts @@ -1,7 +1,8 @@ /** - * 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 { Segmentation, SortedArray } from '../../../../mol-data/int'; @@ -370,7 +371,7 @@ function expandConnected(ctx: QueryContext, structure: Structure) { } const inputUnitA = inputStructure.unitMap.get(unit.id) as Unit.Atomic; - const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order } } = inputUnitA.bonds; + const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order, key } } = inputUnitA.bonds; atomicBond.setStructure(inputStructure); @@ -397,6 +398,7 @@ function expandConnected(ctx: QueryContext, structure: Structure) { atomicBond.b.element = bElement; atomicBond.type = flags[lI]; atomicBond.order = order[lI]; + atomicBond.key = key[lI]; if (atomicBond.test(ctx, true)) { builder.addToUnit(unit.id, bElement); @@ -427,6 +429,7 @@ function expandConnected(ctx: QueryContext, structure: Structure) { atomicBond.b.element = bElement; atomicBond.type = bond.props.flag; atomicBond.order = bond.props.order; + atomicBond.key = bond.props.key; if (atomicBond.test(ctx, true)) { builder.addToUnit(bondedUnit.unitB, bElement); diff --git a/src/mol-model/structure/structure/unit/bonds/data.ts b/src/mol-model/structure/structure/unit/bonds/data.ts index b05df8ed1d0e27a6a5e1c4720741bcc6ae11d356..f2ab500a86fbb09a31bc4f4d72dc6ecd99cf195d 100644 --- a/src/mol-model/structure/structure/unit/bonds/data.ts +++ b/src/mol-model/structure/structure/unit/bonds/data.ts @@ -15,16 +15,17 @@ import { InterUnitGraph } from '../../../../../mol-math/graph/inter-unit-graph'; type IntraUnitBonds = IntAdjacencyGraph<StructureElement.UnitIndex, { readonly order: ArrayLike<number>, readonly flags: ArrayLike<BondType.Flag> + readonly key: ArrayLike<number>, }, { /** can remap even with dynamicBonds on, e.g., for water molecules */ readonly canRemap?: boolean }> namespace IntraUnitBonds { - export const Empty: IntraUnitBonds = IntAdjacencyGraph.create([], [], [], 0, { flags: [], order: [] }); + export const Empty: IntraUnitBonds = IntAdjacencyGraph.create([], [], [], 0, { flags: [], order: [], key: [] }); } -type InterUnitEdgeProps = { readonly order: number, readonly flag: BondType.Flag } +type InterUnitEdgeProps = { readonly order: number, readonly flag: BondType.Flag, readonly key: number } class InterUnitBonds extends InterUnitGraph<number, StructureElement.UnitIndex, InterUnitEdgeProps> { /** Get inter-unit bond given a bond-location */ diff --git a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts index ba0327c3fc2ffaecbc25b4abe2ed8b434a40373d..74f5127df14aabdc3ba3ec71e6ca40ba1c92804c 100644 --- a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts @@ -80,7 +80,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput if (!props.forceCompute && indexPairs) { const { maxDistance } = indexPairs; - const { offset, b, edgeProps: { order, distance, flag } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds; const srcA = sourceIndex.value(aI); const aeI = getElementIdx(type_symbolA.value(aI)); @@ -113,7 +113,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput } if (add) { - builder.add(_aI, _bI, { order: order[i], flag: flag[i] }); + builder.add(_aI, _bI, { order: order[i], flag: flag[i], key: key[i] }); } } continue; // assume `indexPairs` supplies all bonds @@ -131,7 +131,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput // check if the bond is within MAX_RADIUS for this pair of units if (getDistance(unitA, aI, unitB, p.atomIndex) > maxRadius) continue; - builder.add(_aI, _bI, { order: se.order, flag: se.flags }); + builder.add(_aI, _bI, { order: se.order, flag: se.flags, key: se.rowIndex }); added = true; } // assume, for an atom, that if any inter unit bond is given @@ -187,7 +187,8 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput const compIdB = label_comp_idB.value(residueIndexB[bI]); builder.add(_aI, _bI, { order: getInterBondOrderFromTable(compIdA, compIdB, atomIdA, atomIdB), - flag: (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed + flag: (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed, + key: -1 }); } } diff --git a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts index a4be859321bf19f44ea5c7902fff9d373e7565d8..29fd505381b21fd4791c49718f3900b8eeb001cb 100644 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts @@ -24,17 +24,19 @@ import { Model } from '../../../model/model'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) const v3distance = Vec3.distance; -function getGraph(atomA: StructureElement.UnitIndex[], atomB: StructureElement.UnitIndex[], _order: number[], _flags: number[], atomCount: number, canRemap: boolean): IntraUnitBonds { +function getGraph(atomA: StructureElement.UnitIndex[], atomB: StructureElement.UnitIndex[], _order: number[], _flags: number[], _key: number[], atomCount: number, canRemap: boolean): IntraUnitBonds { const builder = new IntAdjacencyGraph.EdgeBuilder(atomCount, atomA, atomB); const flags = new Uint16Array(builder.slotCount); const order = new Int8Array(builder.slotCount); + const key = new Uint32Array(builder.slotCount); for (let i = 0, _i = builder.edgeCount; i < _i; i++) { builder.addNextEdge(); builder.assignProperty(flags, _flags[i]); builder.assignProperty(order, _order[i]); + builder.assignProperty(key, _key[i]); } - return builder.createGraph({ flags, order }, { canRemap }); + return builder.createGraph({ flags, order, key }, { canRemap }); } const tmpDistVecA = Vec3(); @@ -53,7 +55,7 @@ function findIndexPairBonds(unit: Unit.Atomic) { const { type_symbol } = unit.model.atomicHierarchy.atoms; const atomCount = unit.elements.length; const { maxDistance } = indexPairs; - const { offset, b, edgeProps: { order, distance, flag } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds; const { atomSourceIndex: sourceIndex } = unit.model.atomicHierarchy; const { invertedIndex } = Model.getInvertedAtomSourceIndex(unit.model); @@ -62,6 +64,7 @@ function findIndexPairBonds(unit: Unit.Atomic) { const atomB: StructureElement.UnitIndex[] = []; const flags: number[] = []; const orders: number[] = []; + const keys: number[] = []; for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) { const aI = atoms[_aI]; @@ -104,11 +107,12 @@ function findIndexPairBonds(unit: Unit.Atomic) { atomB[atomB.length] = _bI; orders[orders.length] = order[i]; flags[flags.length] = flag[i]; + keys[keys.length] = key[i]; } } } - return getGraph(atomA, atomB, orders, flags, atomCount, false); + return getGraph(atomA, atomB, orders, flags, keys, atomCount, false); } function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBonds { @@ -132,9 +136,10 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon const atomB: StructureElement.UnitIndex[] = []; const flags: number[] = []; const order: number[] = []; + const key: number[] = []; let lastResidue = -1; - let componentMap: Map<string, Map<string, { flags: number, order: number }>> | undefined = void 0; + let componentMap: Map<string, Map<string, { flags: number, order: number, key: number }>> | undefined = void 0; let isWatery = true, isDictionaryBased = true, isSequenced = true; @@ -162,6 +167,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon atomB[atomB.length] = _bI; flags[flags.length] = se.flags; order[order.length] = se.order; + key[key.length] = se.rowIndex; if (!hasStructConn) structConnAdded.clear(); hasStructConn = true; @@ -230,6 +236,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon flag |= BondType.Flag.MetallicCoordination; } flags[flags.length] = flag; + key[key.length] = e.key; } continue; } @@ -243,6 +250,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon atomB[atomB.length] = _bI; order[order.length] = getIntraBondOrderFromTable(compId, atomIdA, label_atom_id.value(bI)); flags[flags.length] = (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed; + key[key.length] = -1; const seqIdB = label_seq_id.value(rbI); @@ -253,7 +261,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon } const canRemap = isWatery || (isDictionaryBased && isSequenced); - return getGraph(atomA, atomB, order, flags, atomCount, canRemap); + return getGraph(atomA, atomB, order, flags, key, atomCount, canRemap); } function computeIntraUnitBonds(unit: Unit.Atomic, props?: Partial<BondComputationProps>) { diff --git a/src/mol-script/language/symbol-table/structure-query.ts b/src/mol-script/language/symbol-table/structure-query.ts index 9e765f41649288a054b01a69b4a6a7d06b1c2bf6..209da4376e81c413caada96b2a2b544146e3de48 100644 --- a/src/mol-script/language/symbol-table/structure-query.ts +++ b/src/mol-script/language/symbol-table/structure-query.ts @@ -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> @@ -333,6 +333,7 @@ const bondProperty = { flags: bondProp(Types.BondFlags), order: bondProp(Type.Num), + key: bondProp(Type.Num), length: bondProp(Type.Num), atomA: bondProp(Types.ElementReference), atomB: bondProp(Types.ElementReference) @@ -356,5 +357,5 @@ export const structureQuery = { combinator, atomSet, atomProperty, - bondProperty: bondProperty + bondProperty }; \ No newline at end of file diff --git a/src/mol-script/runtime/query/table.ts b/src/mol-script/runtime/query/table.ts index dc32f889628e0958a518ed074a31cbb8390d4780..dcb18e9fef74f4744f7d7e92625e29943a1ca0e4 100644 --- a/src/mol-script/runtime/query/table.ts +++ b/src/mol-script/runtime/query/table.ts @@ -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> @@ -356,6 +356,7 @@ const symbols = [ // ============= BOND PROPERTIES ================ D(MolScript.structureQuery.bondProperty.order, (ctx, xs) => ctx.atomicBond.order), D(MolScript.structureQuery.bondProperty.flags, (ctx, xs) => ctx.atomicBond.type), + D(MolScript.structureQuery.bondProperty.key, (ctx, xs) => ctx.atomicBond.key), D(MolScript.structureQuery.bondProperty.atomA, (ctx, xs) => ctx.atomicBond.a), D(MolScript.structureQuery.bondProperty.atomB, (ctx, xs) => ctx.atomicBond.b), D(MolScript.structureQuery.bondProperty.length, (ctx, xs) => ctx.atomicBond.length),