diff --git a/CHANGELOG.md b/CHANGELOG.md index 3226c2d309d8cc72f09a38e7879468fe8c8e42c5..e3de459f2e6d705653c9f7b88e289565859242c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Note that since we don't clearly distinguish between a public and private interf - Fix cylinder near-clipping - Add interior cylinder caps - Add per-pixel object clipping +- Fix `QualityAssessment` assignment bug for structures with different auth vs label sequence numbering ## [v3.26.0] - 2022-12-04 diff --git a/src/extensions/model-archive/quality-assessment/prop.ts b/src/extensions/model-archive/quality-assessment/prop.ts index ce8c1a3975a92800bdca1f0a334f899a1767221a..717a6f0889fee12c0c52d5c96c6afa3bbd77afe6 100644 --- a/src/extensions/model-archive/quality-assessment/prop.ts +++ b/src/extensions/model-archive/quality-assessment/prop.ts @@ -2,6 +2,7 @@ * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> + * @author David Sehnal <david.sehnal@gmail.com> */ import { ParamDefinition as PD } from '../../../mol-util/param-definition'; @@ -14,6 +15,7 @@ import { CustomPropSymbol } from '../../../mol-script/language/symbol'; import { Type } from '../../../mol-script/language/type'; import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif'; +import { AtomicIndex } from '../../../mol-model/structure/model/properties/atomic'; export { QualityAssessment }; @@ -71,14 +73,28 @@ namespace QualityAssessment { localNames.set(ma_qa_metric.id.value(i), name); } + const residueKey: AtomicIndex.ResidueLabelKey = { + label_entity_id: '', + label_asym_id: '', + label_seq_id: 0, + pdbx_PDB_ins_code: undefined, + }; + for (let i = 0, il = ma_qa_metric_local._rowCount; i < il; i++) { if (model_id.value(i) !== model.modelNum) continue; const labelAsymId = label_asym_id.value(i); const entityIndex = index.findEntity(labelAsymId); - const rI = index.findResidue(model.entities.data.id.value(entityIndex), labelAsymId, label_seq_id.value(i)); - const name = localNames.get(metric_id.value(i))!; - localMetrics.get(name)!.set(rI, metric_value.value(i)); + + residueKey.label_entity_id = model.entities.data.id.value(entityIndex); + residueKey.label_asym_id = labelAsymId; + residueKey.label_seq_id = label_seq_id.value(i); + + const rI = index.findResidueLabel(residueKey); + if (rI >= 0) { + const name = localNames.get(metric_id.value(i))!; + localMetrics.get(name)!.set(rI, metric_value.value(i)); + } } return { diff --git a/src/mol-model/structure/model/properties/atomic/hierarchy.ts b/src/mol-model/structure/model/properties/atomic/hierarchy.ts index 5346163be4be48c9d6b3dd0a75c84d9b3ed05a6b..4ef8d5279a9e28abf5a4fe3c0c6c604ef73f68d1 100644 --- a/src/mol-model/structure/model/properties/atomic/hierarchy.ts +++ b/src/mol-model/structure/model/properties/atomic/hierarchy.ts @@ -166,6 +166,14 @@ export interface AtomicIndex { findResidue(key: AtomicIndex.ResidueKey): ResidueIndex, findResidue(label_entity_id: string, label_asym_id: string, auth_seq_id: number, pdbx_PDB_ins_code?: string): ResidueIndex, + + /** + * Index of the 1st occurence of this residue using "all-label" address. + * Doesn't work for "ligands" as they don't have a label seq id assigned. + * @returns index or -1 if not present. + */ + findResidueLabel(key: AtomicIndex.ResidueLabelKey): ResidueIndex, + /** * Index of the 1st occurence of this residue. * @param key.pdbx_PDB_ins_code Empty string for undefined diff --git a/src/mol-model/structure/model/properties/utils/atomic-index.ts b/src/mol-model/structure/model/properties/utils/atomic-index.ts index 8f603282be7b09e42ca27ef8e39d7bb645a52278..cbd09a722aaa56c5cb10510e63686097ac1f5d19 100644 --- a/src/mol-model/structure/model/properties/utils/atomic-index.ts +++ b/src/mol-model/structure/model/properties/utils/atomic-index.ts @@ -124,6 +124,14 @@ class Index implements AtomicIndex { return rm.has(id) ? rm.get(id)! : -1 as ResidueIndex; } + findResidueLabel(key: AtomicIndex.ResidueLabelKey): ResidueIndex { + const cI = this.findChainLabel(key); + if (cI < 0) return -1 as ResidueIndex; + const rm = this.map.chain_index_label_seq_id.get(cI)!; + const id = getResidueId(key.label_seq_id, key.pdbx_PDB_ins_code || ''); + return rm.has(id) ? rm.get(id)! : -1 as ResidueIndex; + } + findResidueAuth(key: AtomicIndex.ResidueAuthKey): ResidueIndex { const cI = this.findChainAuth(key); if (cI < 0) return -1 as ResidueIndex;