diff --git a/src/apps/rednatco/step.ts b/src/apps/rednatco/step.ts index a988acfad6ba227bbb428fe59a9a9db5d86905fd..2bc7766179c82150ee2171180bcc15098a2ddfb7 100644 --- a/src/apps/rednatco/step.ts +++ b/src/apps/rednatco/step.ts @@ -3,25 +3,44 @@ import { StructureElement, StructureProperties } from '../../mol-model/structure import { Location } from '../../mol-model/structure/structure/element/location'; export namespace Step { - export type Description = { + export interface Description { + name: string; model: number; entryId: string; chain: string; resNo1: number; - comp1: string; + compId1: string; altId1?: string; - insCode1?: string; + insCode1: string; resNo2: number; - comp2: string; + compId2: string; altId2?: string; - insCode2?: string; + insCode2: string; }; - function nameResidue(seqId: number, compId: string, altId?: string, insCode?: string) { - return `${compId}${altId ? `.${altId}` : ''}_${seqId}${insCode ? `.${insCode}` : '' }`; + export interface ExtendedDescription extends Description{ + assignedNtC: string; + closestNtC: string; + }; + + function nameResidue(seqId: number, compId: string, altId: string|undefined, insCode: string) { + return `${compId}${altId ? `.${altId}` : ''}_${seqId}${insCode !== '' ? `.${insCode}` : '' }`; + } + + function nameStep( + entryId: string, + modelNum: number, asymId: string, + seqId1: number, compId1: string, altId1: string|undefined, insCode1: string, + seqId2: number, compId2: string, altId2: string|undefined, insCode2: string, + multipleModels: boolean + ) { + const res1 = nameResidue(seqId1, compId1, altId1, insCode1); + const res2 = nameResidue(seqId2, compId2, altId2, insCode2); + + return `${entryId}${multipleModels ? `-m${modelNum}` : ''}_${asymId}_${res1}_${res2}`; } - function residueDescription(a: string, b: string): { comp: string, altId?: string, resNo: number, insCode?: string }|undefined { + function residueDescription(a: string, b: string): { comp: string, altId?: string, resNo: number, insCode: string }|undefined { const toksA = a.split('.'); const toksB = b.split('.'); @@ -36,35 +55,37 @@ export namespace Step { comp: toksA[0], altId: toksA.length === 2 ? toksA[1] : void 0, resNo, - insCode: toksB.length === 2 ? toksB[1] : void 0, + insCode: toksB.length === 2 ? toksB[1] : '', }; } - export function describe(loci: StructureElement.Loci) { + export function describe(loci: StructureElement.Loci, multipleModels: boolean) { const es = loci.elements[0]; // Ignore multiple selections const loc = Location.create(loci.structure, es.unit); loc.element = es.unit.elements[OrderedSet.getAt(es.indices, 0)]; // We're assuming a non-empty set const description: Description = { + name: '', model: es.unit.model.modelNum, entryId: loci.structure.model.entryId.toLowerCase(), chain: StructureProperties.chain.auth_asym_id(loc), resNo1: StructureProperties.residue.auth_seq_id(loc), - comp1: StructureProperties.atom.auth_comp_id(loc), - altId1: StructureProperties.atom.label_alt_id(loc), + compId1: StructureProperties.atom.auth_comp_id(loc), + altId1: StructureProperties.atom.label_alt_id(loc) === '' ? void 0 : StructureProperties.atom.label_alt_id(loc), insCode1: StructureProperties.residue.pdbx_PDB_ins_code(loc), resNo2: -1, - comp2: '', + compId2: '', altId2: void 0, - insCode2: void 0, + insCode2: '', }; let found = false; const len = OrderedSet.size(es.indices); + const labelResNo = StructureProperties.residue.label_seq_id(loc); for (let idx = 1; idx < len; idx++) { loc.element = es.unit.elements[OrderedSet.getAt(es.indices, idx)]; - if (StructureProperties.residue.auth_seq_id(loc) !== description.resNo1) { + if (StructureProperties.residue.label_seq_id(loc) !== labelResNo) { found = true; break; } @@ -74,26 +95,34 @@ export namespace Step { return void 0; description.resNo2 = StructureProperties.residue.auth_seq_id(loc); - description.comp2 = StructureProperties.atom.auth_comp_id(loc); - description.altId2 = StructureProperties.atom.label_alt_id(loc); + description.compId2 = StructureProperties.atom.auth_comp_id(loc); + description.altId2 = StructureProperties.atom.label_alt_id(loc) === '' ? void 0 : StructureProperties.atom.label_alt_id(loc); description.insCode2 = StructureProperties.residue.pdbx_PDB_ins_code(loc); + description.name = nameStep( + description.entryId, + description.model, description.chain, + description.resNo1, description.compId1, description.altId1, description.insCode1, + description.resNo2, description.compId2, description.altId2, description.insCode2, + multipleModels + ); return description; } export function fromName(name: string) { const description: Description = { + name: '', model: -1, entryId: '', chain: '', resNo1: -1, - comp1: '', + compId1: '', altId1: void 0, - insCode1: void 0, + insCode1: '', resNo2: -1, - comp2: '', + compId2: '', altId2: void 0, - insCode2: void 0, + insCode2: '', }; const toks = name.split('_'); @@ -140,13 +169,14 @@ export namespace Step { } description.resNo1 = res1.resNo; - description.comp1 = res1.comp; + description.compId1 = res1.comp; description.altId1 = res1.altId; description.insCode1 = res1.insCode; description.resNo2 = res2.resNo; - description.comp2 = res2.comp; + description.compId2 = res2.comp; description.altId2 = res2.altId; description.insCode2 = res2.insCode; + description.name = name; return description; } @@ -170,11 +200,4 @@ export namespace Step { return false; } - - export function name(description: Description, multipleModels: boolean) { - const res1 = nameResidue(description.resNo1, description.comp1, description.altId1, description.insCode1); - const res2 = nameResidue(description.resNo2, description.comp2, description.altId2, description.insCode2); - - return `${description.entryId}${multipleModels ? `-m${description.model}` : ''}_${description.chain}_${res1}_${res2}`; - } } diff --git a/src/apps/rednatco/viewer.ts b/src/apps/rednatco/viewer.ts index 8540db32c74cd3f96b45ce793febe8b7f4cf4c5f..2edc54ee3cc5651f70479612f8e1159cebbdcac5 100644 --- a/src/apps/rednatco/viewer.ts +++ b/src/apps/rednatco/viewer.ts @@ -55,22 +55,6 @@ const NtCSupSel = 'ntc-sup-sel'; const NtCSupNext = 'ntc-sup-next'; const SphereBoundaryHelper = new BoundaryHelper('98'); -type StepInfo = { - name: string; - assignedNtC: string; - closestNtC: string; - chain: string; - resNo1: number; - resNo2: number; - compId1: string; - compId2: string; - altId1?: string; - altId2?: string; - insCode1: string; - insCode2: string; - model: number; -} - function superpositionAtomsIndices(loci: StructureElement.Loci) { const es = loci.elements[0]; const loc = Location.create(loci.structure, es.unit, es.unit.elements[OrderedSet.getAt(es.indices, 0)]); @@ -249,7 +233,7 @@ const ReDNATCOLociSelectionProvider = PluginBehavior.create({ export class ReDNATCOMspViewer { private haveMultipleModels = false; - private steps: StepInfo[] = []; + private steps: Step.ExtendedDescription[] = []; private stepNames: Map<string, number> = new Map(); private app: ReDNATCOMsp; @@ -671,12 +655,12 @@ export class ReDNATCOMspViewer { this.focusOnLoci(focusOn); } - gatherStepInfo(): { steps: StepInfo[], stepNames: Map<string, number> }|undefined { + gatherStepInfo(): { steps: Step.ExtendedDescription[], stepNames: Map<string, number> }|undefined { const obj = this.plugin.state.data.cells.get(IDs.ID('model', '', BaseRef))?.obj; if (!obj) return void 0; - const model = (obj as StateObject<Model>); - const sourceData = model.data.sourceData; + const struModel = (obj as StateObject<Model>); + const sourceData = struModel.data.sourceData; if (!MmcifFormat.is(sourceData)) return void 0; @@ -709,7 +693,7 @@ export class ReDNATCOMspViewer { const len = _ids.length; const stepNames = new Map<string, number>(); - const steps = new Array<StepInfo>(len); + const steps = new Array<Step.ExtendedDescription>(len); for (let idx = 0; idx < len; idx++) { const id = _ids[idx]; @@ -732,6 +716,8 @@ export class ReDNATCOMspViewer { // We're assuming that steps are ID'd with a contigious, monotonic sequence starting from 1 steps[id - 1] = { name, + model, + entryId: struModel.data.entryId, assignedNtC, closestNtC, chain, @@ -743,7 +729,6 @@ export class ReDNATCOMspViewer { altId2, insCode1, insCode2, - model }; stepNames.set(name, id - 1); break; @@ -941,11 +926,9 @@ export class ReDNATCOMspViewer { const loci = Loci.normalize(selected.loci, 'two-residues'); if (loci.kind === 'element-loci') { - const stepDesc = Step.describe(loci); - if (stepDesc) { - const stepName = Step.name(stepDesc, this.haveMultipleModels); - this.app.viewerStepSelected(stepName); - } + const stepDesc = Step.describe(loci, this.haveMultipleModels); + if (stepDesc && this.stepNames.has(stepDesc.name)) + this.app.viewerStepSelected(stepDesc.name); } }