From bc91f0d3ff181d2037fc2504b598ba8eb0472cd7 Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Wed, 24 Jul 2019 07:35:03 +0200 Subject: [PATCH] Support multiple models in StructureElement.Loci.toScriptExpression --- src/mol-model/structure/structure/element.ts | 38 ++++++++++++------- .../structure/structure/properties.ts | 2 + .../structure/structure/structure.ts | 4 ++ .../language/symbol-table/structure-query.ts | 2 + src/mol-script/runtime/query/table.ts | 2 + src/mol-script/script/mol-script/symbols.ts | 2 + 6 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index ab0abf5b3..6c84a030a 100644 --- a/src/mol-model/structure/structure/element.ts +++ b/src/mol-model/structure/structure/element.ts @@ -309,24 +309,24 @@ namespace StructureElement { } export function toScriptExpression(loci: Loci) { - if (loci.structure.models.length > 1) { - console.warn('toScriptExpression is only supported for Structure with single model, returning empty expression.'); - return MS.struct.generator.empty(); - } if (loci.elements.length === 0) return MS.struct.generator.empty(); - const sourceIndexMap = new Map<string, UniqueArray<number, number>>(); + const models = loci.structure.models; + const sourceIndexMap = new Map<string, { modelLabel: string, modelIndex: number, xs: UniqueArray<number, number> }>(); const el = StructureElement.create(), p = StructureProperties.atom.sourceIndex; for (const e of loci.elements) { const { indices } = e; const { elements } = e.unit; - const opName = e.unit.conformation.operator.name; + + const key = models.length === 1 + ? e.unit.conformation.operator.name + : `${e.unit.conformation.operator.name} ${e.unit.model.label} ${e.unit.model.modelNum}`; let sourceIndices: UniqueArray<number, number>; - if (sourceIndexMap.has(opName)) sourceIndices = sourceIndexMap.get(opName)!; + if (sourceIndexMap.has(key)) sourceIndices = sourceIndexMap.get(key)!.xs; else { sourceIndices = UniqueArray.create<number, number>(); - sourceIndexMap.set(opName, sourceIndices); + sourceIndexMap.set(key, { modelLabel: e.unit.model.label, modelIndex: e.unit.model.modelNum, xs: sourceIndices }); } el.unit = e.unit; @@ -342,7 +342,8 @@ namespace StructureElement { while (true) { const k = keys.next(); if (k.done) break; - byOpName.push(getOpNameQuery(k.value, sourceIndexMap.get(k.value)!.array)); + const e = sourceIndexMap.get(k.value)!; + byOpName.push(getOpNameQuery(k.value, e.xs.array, models.length > 1, e.modelLabel, e.modelIndex)); } return MS.struct.modifier.union([ @@ -350,7 +351,7 @@ namespace StructureElement { ]); } - function getOpNameQuery(opName: string, xs: number[]) { + function getOpNameQuery(opName: string, xs: number[], multimodel: boolean, modelLabel: string, modelIndex: number) { sortArray(xs); const ranges: number[] = []; @@ -384,10 +385,19 @@ namespace StructureElement { tests[tests.length] = MS.core.rel.inRange([siProp, ranges[2 * rI], ranges[2 * rI + 1]]); } - return MS.struct.generator.atomGroups({ - 'atom-test': tests.length > 1 ? MS.core.logic.or(tests) : tests[0], - 'chain-test': MS.core.rel.eq([MS.struct.atomProperty.core.operatorName(), opName]) - }); + return multimodel + ? MS.struct.generator.atomGroups({ + 'atom-test': tests.length > 1 ? MS.core.logic.or(tests) : tests[0], + 'chain-test': MS.core.rel.eq([MS.struct.atomProperty.core.operatorName(), opName]), + 'entity-test': MS.core.logic.and([ + MS.core.rel.eq([MS.struct.atomProperty.core.modelLabel(), modelLabel]), + MS.core.rel.eq([MS.struct.atomProperty.core.modelIndex(), modelIndex]), + ]) + }) + : MS.struct.generator.atomGroups({ + 'atom-test': tests.length > 1 ? MS.core.logic.or(tests) : tests[0], + 'chain-test': MS.core.rel.eq([MS.struct.atomProperty.core.operatorName(), opName]) + }); } } } diff --git a/src/mol-model/structure/structure/properties.ts b/src/mol-model/structure/structure/properties.ts index 17aa1c75a..5c6a70a0d 100644 --- a/src/mol-model/structure/structure/properties.ts +++ b/src/mol-model/structure/structure/properties.ts @@ -113,6 +113,8 @@ const entity = { const unit = { id: StructureElement.property(l => l.unit.id), operator_name: StructureElement.property(l => l.unit.conformation.operator.name), + model_index: StructureElement.property(l => l.unit.model.modelNum), + model_label: StructureElement.property(l => l.unit.model.label), hkl: StructureElement.property(l => l.unit.conformation.operator.hkl), spgrOp: StructureElement.property(l => l.unit.conformation.operator.spgrOp), diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index d91b02346..000cc0a7b 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -218,6 +218,10 @@ class Structure { return SortedArray.has(this.unitMap.get(e.unit.id).elements, e.element); } + getModelIndex(m: Model) { + return this.model + } + private initUnits(units: ArrayLike<Unit>) { const map = IntMap.Mutable<Unit>(); let elementCount = 0; diff --git a/src/mol-script/language/symbol-table/structure-query.ts b/src/mol-script/language/symbol-table/structure-query.ts index 3a6ed1846..b129ba319 100644 --- a/src/mol-script/language/symbol-table/structure-query.ts +++ b/src/mol-script/language/symbol-table/structure-query.ts @@ -254,6 +254,8 @@ 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.'), + 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.') }, topology: { diff --git a/src/mol-script/runtime/query/table.ts b/src/mol-script/runtime/query/table.ts index e2d75927f..ee5e68247 100644 --- a/src/mol-script/runtime/query/table.ts +++ b/src/mol-script/runtime/query/table.ts @@ -247,6 +247,8 @@ 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.modelIndex, atomProp(StructureProperties.unit.model_index)), + D(MolScript.structureQuery.atomProperty.core.modelLabel, atomProp(StructureProperties.unit.model_label)), D(MolScript.structureQuery.atomProperty.core.atomKey, (ctx, _) => cantorPairing(ctx.element.unit.id, ctx.element.element)), // TODO: diff --git a/src/mol-script/script/mol-script/symbols.ts b/src/mol-script/script/mol-script/symbols.ts index 4216867f9..eaa70e133 100644 --- a/src/mol-script/script/mol-script/symbols.ts +++ b/src/mol-script/script/mol-script/symbols.ts @@ -199,6 +199,8 @@ 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.modelIndex, 'atom.model-index'), + Alias(MolScript.structureQuery.atomProperty.core.modelLabel, 'atom.model-label'), Alias(MolScript.structureQuery.atomProperty.core.atomKey, 'atom.key'), Alias(MolScript.structureQuery.atomProperty.core.bondCount, 'atom.bond-count'), -- GitLab