diff --git a/src/mol-math/geometry/symmetry-operator.ts b/src/mol-math/geometry/symmetry-operator.ts index 3f848728976d022c1199434f64f17237d9d77db4..cbc2a5eda01f3d26d0f059e3e496d6743f8a4de9 100644 --- a/src/mol-math/geometry/symmetry-operator.ts +++ b/src/mol-math/geometry/symmetry-operator.ts @@ -1,11 +1,11 @@ /** - * Copyright (c) 2017 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 { lerp as scalar_lerp } from '../../mol-math/interpolate'; -import { defaults } from '../../mol-util'; import { Mat3 } from '../linear-algebra/3d/mat3'; import { Mat4 } from '../linear-algebra/3d/mat4'; import { Quat } from '../linear-algebra/3d/quat'; @@ -29,11 +29,13 @@ interface SymmetryOperator { readonly hkl: Vec3, /** spacegroup symmetry operator index, -1 if not applicable */ readonly spgrOp: number, + /** unique (external) key, -1 if not available */ + readonly key: number, readonly matrix: Mat4, - // cache the inverse of the transform + /** cache the inverse of the transform */ readonly inverse: Mat4, - // optimize the identity case + /** optimize the identity case */ readonly isIdentity: boolean, /** @@ -51,19 +53,20 @@ namespace SymmetryOperator { export const RotationTranslationEpsilon = 0.005; - export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number } + export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number, key?: number } export function create(name: string, matrix: Mat4, info?: CreateInfo | SymmetryOperator): SymmetryOperator { - let { assembly, ncsId, hkl, spgrOp } = info || { }; + let { assembly, ncsId, hkl, spgrOp, key } = info || { }; const _hkl = hkl ? Vec3.clone(hkl) : Vec3(); - spgrOp = defaults(spgrOp, -1); + spgrOp = spgrOp ?? -1; + key = key ?? -1; ncsId = ncsId || -1; const isIdentity = Mat4.isIdentity(matrix); const suffix = getSuffix(info, isIdentity); - if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix }; + if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix, key }; if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) { console.warn(`Symmetry operator (${name}) should be a composition of rotation and translation.`); } - return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, ncsId, suffix }; + return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, key, ncsId, suffix }; } function isSymmetryOperator(x: any): x is SymmetryOperator { diff --git a/src/mol-model-formats/structure/property/bonds/index-pair.ts b/src/mol-model-formats/structure/property/bonds/index-pair.ts index c6021eb47183f67a6fee53a8bda06a2183f2e60a..99eb988e7e185d8297d2c71f66e4733dbdec5075 100644 --- a/src/mol-model-formats/structure/property/bonds/index-pair.ts +++ b/src/mol-model-formats/structure/property/bonds/index-pair.ts @@ -14,6 +14,8 @@ import { ElementIndex } from '../../../../mol-model/structure'; export type IndexPairsProps = { readonly key: ArrayLike<number> + /** Sorted contor-paired operator keys */ + readonly operator: ArrayLike<number> readonly order: ArrayLike<number> readonly distance: ArrayLike<number> readonly flag: ArrayLike<BondType.Flag> @@ -24,18 +26,20 @@ export type IndexPairBonds = { bonds: IndexPairs, maxDistance: number } function getGraph(indexA: ArrayLike<ElementIndex>, indexB: ArrayLike<ElementIndex>, props: Partial<IndexPairsProps>, count: number): IndexPairs { const builder = new IntAdjacencyGraph.EdgeBuilder(count, indexA, indexB); const key = new Int32Array(builder.slotCount); + const operator = new Array(builder.slotCount); const order = new Int8Array(builder.slotCount); const distance = new Array(builder.slotCount); const flag = new Array(builder.slotCount); for (let i = 0, _i = builder.edgeCount; i < _i; i++) { builder.addNextEdge(); builder.assignProperty(key, props.key ? props.key[i] : -1); + builder.assignProperty(operator, props.operator ? props.operator[i] : -1); builder.assignProperty(order, props.order ? props.order[i] : 1); builder.assignProperty(distance, props.distance ? props.distance[i] : -1); builder.assignProperty(flag, props.flag ? props.flag[i] : BondType.Flag.Covalent); } - return builder.createGraph({ key, order, distance, flag }); + return builder.createGraph({ key, operator, order, distance, flag }); } export namespace IndexPairBonds { @@ -50,6 +54,10 @@ export namespace IndexPairBonds { indexA: Column<number>, indexB: Column<number>, key?: Column<number>, + /** + * Sorted contor-paired operator keys. Used in bond computation. + */ + operator?: Column<number>, order?: Column<number>, /** * Useful for bonds in periodic cells. That is, only bonds within the given @@ -83,11 +91,12 @@ export namespace IndexPairBonds { const indexA = pairs.indexA.toArray() as ArrayLike<ElementIndex>; const indexB = pairs.indexB.toArray() as ArrayLike<ElementIndex>; const key = pairs.key && pairs.key.toArray(); + const operator = pairs.operator && pairs.operator.toArray(); const order = pairs.order && pairs.order.toArray(); const distance = pairs.distance && pairs.distance.toArray(); const flag = pairs.flag && pairs.flag.toArray(); return { - bonds: getGraph(indexA, indexB, { key, order, distance, flag }, count), + bonds: getGraph(indexA, indexB, { key, operator, order, distance, flag }, count), maxDistance: p.maxDistance }; } diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts index c51b441a77da6cfffd623877b0734df8e87fc757..7cf7070a41db2e78ce0fbef36e706b873b872b98 100644 --- a/src/mol-model/structure/query/context.ts +++ b/src/mol-model/structure/query/context.ts @@ -155,6 +155,6 @@ class QueryContextBondInfo<U extends Unit = Unit> { } get length() { - return StructureElement.Location.distance(this.a, this. b); + return StructureElement.Location.distance(this.a, this.b); } } \ No newline at end of file diff --git a/src/mol-model/structure/structure/properties.ts b/src/mol-model/structure/structure/properties.ts index 1ee3110f99cea729f8561224c2056042774763ac..71e003b232d9dd679a624d9162f792b683dc993c 100644 --- a/src/mol-model/structure/structure/properties.ts +++ b/src/mol-model/structure/structure/properties.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -173,6 +173,7 @@ const unit = { multiChain: p(l => Unit.Traits.is(l.unit.traits, Unit.Trait.MultiChain)), object_primitive: p(l => l.unit.objectPrimitive), operator_name: p(l => l.unit.conformation.operator.name), + operator_key: p(l => l.unit.conformation.operator.key), model_index: p(l => l.unit.model.modelNum), model_label: p(l => l.unit.model.label), model_entry_id: p(l => l.unit.model.entryId), 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 74f5127df14aabdc3ba3ec71e6ca40ba1c92804c..2585e4c850423cf0558aeba61d46ce7956e30b80 100644 --- a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts @@ -20,6 +20,7 @@ import { InterUnitGraph } from '../../../../../mol-math/graph/inter-unit-graph'; import { StructConn } from '../../../../../mol-model-formats/structure/property/bonds/struct_conn'; import { equalEps } from '../../../../../mol-math/linear-algebra/3d/common'; import { Model } from '../../../model'; +import { sortedCantorPairing } from '../../../../../mol-data/util'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) const v3distance = Vec3.distance; @@ -71,6 +72,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput const testDistanceSq = (bRadius + maxRadius) * (bRadius + maxRadius); builder.startUnitPair(unitA.id, unitB.id); + const opPairKey = sortedCantorPairing(unitA.conformation.operator.key, unitB.conformation.operator.key); for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) { const aI = atomsA[_aI]; @@ -80,7 +82,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, key } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key, operator } } = indexPairs.bonds; const srcA = sourceIndex.value(aI); const aeI = getElementIdx(type_symbolA.value(aI)); @@ -90,6 +92,9 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput const _bI = SortedArray.indexOf(unitB.elements, bI) as StructureElement.UnitIndex; if (_bI < 0) continue; + const op = operator[i]; + if (op >= 0 && opPairKey !== op) continue; + const beI = getElementIdx(type_symbolA.value(bI)); const d = distance[i]; 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 29fd505381b21fd4791c49718f3900b8eeb001cb..67d89caac6753787379ea4bb84b6fe1860634f29 100644 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts @@ -20,6 +20,7 @@ import { Vec3 } from '../../../../../mol-math/linear-algebra'; import { ElementIndex } from '../../../model/indexing'; import { equalEps } from '../../../../../mol-math/linear-algebra/3d/common'; import { Model } from '../../../model/model'; +import { sortedCantorPairing } from '../../../../../mol-data/util'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) const v3distance = Vec3.distance; @@ -55,7 +56,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, key } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key, operator } } = indexPairs.bonds; const { atomSourceIndex: sourceIndex } = unit.model.atomicHierarchy; const { invertedIndex } = Model.getInvertedAtomSourceIndex(unit.model); @@ -66,6 +67,8 @@ function findIndexPairBonds(unit: Unit.Atomic) { const orders: number[] = []; const keys: number[] = []; + const opPairKey = sortedCantorPairing(unit.conformation.operator.key, unit.conformation.operator.key); + for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) { const aI = atoms[_aI]; const aeI = getElementIdx(type_symbol.value(aI)); @@ -80,6 +83,9 @@ function findIndexPairBonds(unit: Unit.Atomic) { const _bI = SortedArray.indexOf(unit.elements, bI) as StructureElement.UnitIndex; if (_bI < 0) continue; + const op = operator[i]; + if (op >= 0 && opPairKey !== op) continue; + const beI = getElementIdx(type_symbol.value(bI)); const d = distance[i]; diff --git a/src/mol-script/language/symbol-table/structure-query.ts b/src/mol-script/language/symbol-table/structure-query.ts index 209da4376e81c413caada96b2a2b544146e3de48..e7125a35814c22831970ee0571f198158e9df89a 100644 --- a/src/mol-script/language/symbol-table/structure-query.ts +++ b/src/mol-script/language/symbol-table/structure-query.ts @@ -273,6 +273,7 @@ const atomProperty = { sourceIndex: atomProp(Type.Num, 'Index of the atom/element in the input file.'), operatorName: atomProp(Type.Str, 'Name of the symmetry operator applied to this element.'), + operatorKey: atomProp(Type.Num, 'Key of the symmetry operator applied to this element.'), modelIndex: atomProp(Type.Num, 'Index of the model in the input file.'), modelLabel: atomProp(Type.Str, 'Label/header of the model in the input file.') }, diff --git a/src/mol-script/runtime/query/table.ts b/src/mol-script/runtime/query/table.ts index deab2d4baa0c10ab7fc3641b258ef8a1c7a0cce2..a87b23c7e6509c4324585904548578e9f8f10dd6 100644 --- a/src/mol-script/runtime/query/table.ts +++ b/src/mol-script/runtime/query/table.ts @@ -299,6 +299,7 @@ const symbols = [ D(MolScript.structureQuery.atomProperty.core.z, atomProp(StructureProperties.atom.z)), D(MolScript.structureQuery.atomProperty.core.sourceIndex, atomProp(StructureProperties.atom.sourceIndex)), D(MolScript.structureQuery.atomProperty.core.operatorName, atomProp(StructureProperties.unit.operator_name)), + D(MolScript.structureQuery.atomProperty.core.operatorKey, atomProp(StructureProperties.unit.operator_key)), D(MolScript.structureQuery.atomProperty.core.modelIndex, atomProp(StructureProperties.unit.model_index)), D(MolScript.structureQuery.atomProperty.core.modelLabel, atomProp(StructureProperties.unit.model_label)), D(MolScript.structureQuery.atomProperty.core.atomKey, (ctx, xs) => { diff --git a/src/mol-script/script/mol-script/symbols.ts b/src/mol-script/script/mol-script/symbols.ts index c4bd1cfe251bba567bfdd89eabc319cea26ece99..feb891928cd41da4977ee58ffee8132a15ed0601 100644 --- a/src/mol-script/script/mol-script/symbols.ts +++ b/src/mol-script/script/mol-script/symbols.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 { UniqueArray } from '../../../mol-data/generic'; @@ -205,6 +206,7 @@ export const SymbolTable = [ Alias(MolScript.structureQuery.atomProperty.core.z, 'atom.z'), Alias(MolScript.structureQuery.atomProperty.core.sourceIndex, 'atom.src-index'), Alias(MolScript.structureQuery.atomProperty.core.operatorName, 'atom.op-name'), + Alias(MolScript.structureQuery.atomProperty.core.operatorKey, 'atom.op-key'), Alias(MolScript.structureQuery.atomProperty.core.modelIndex, 'atom.model-index'), Alias(MolScript.structureQuery.atomProperty.core.modelLabel, 'atom.model-label'), Alias(MolScript.structureQuery.atomProperty.core.atomKey, 'atom.key'), @@ -253,6 +255,7 @@ export const SymbolTable = [ 'Bond Properties', Alias(MolScript.structureQuery.bondProperty.order, 'bond.order'), Alias(MolScript.structureQuery.bondProperty.length, 'bond.length'), + Alias(MolScript.structureQuery.bondProperty.key, 'bond.key'), Alias(MolScript.structureQuery.bondProperty.atomA, 'bond.atom-a'), Alias(MolScript.structureQuery.bondProperty.atomB, 'bond.atom-b'), Macro(MSymbol('bond.is', Arguments.List(StructureQueryTypes.BondFlag), Type.Bool,