Skip to content
Snippets Groups Projects
Commit 9633bf70 authored by David Sehnal's avatar David Sehnal
Browse files

Mod residues mmCIF export, segmentation data model fixes, other fixes

parent e8df2a65
No related branches found
No related tags found
No related merge requests found
......@@ -119,7 +119,7 @@ export function printSequence(model: Model) {
export function printModRes(model: Model) {
console.log('\nModified Residues\n=============');
const map = model.properties.modifiedResidueNameMap;
const map = model.properties.modifiedResidues.parentId;
const { label_comp_id, _rowCount } = model.atomicHierarchy.residues;
for (let i = 0; i < _rowCount; i++) {
const comp_id = label_comp_id.value(i);
......
......@@ -50,18 +50,18 @@ export function projectValue({ offsets }: Segmentation, set: OrderedSet, value:
return OrderedSet.findRange(set, OrderedSet.getAt(offsets, idx), OrderedSet.getAt(offsets, idx + 1) - 1);
}
export class SegmentIterator<T extends number = number> implements Iterator<Segs.Segment<T>> {
export class SegmentIterator<I extends number = number> implements Iterator<Segs.Segment<I>> {
private segmentMin = 0;
private segmentMax = 0;
private setRange = Interval.Empty;
private value: Segs.Segment<T> = { index: 0, start: 0 as T, end: 0 as T };
private value: Segs.Segment<I> = { index: 0 as I, start: 0, end: 0 };
hasNext: boolean = false;
move() {
while (this.hasNext) {
if (this.updateValue()) {
this.value.index = this.segmentMin++;
this.value.index = this.segmentMin++ as I;
this.hasNext = this.segmentMax >= this.segmentMin && Interval.size(this.setRange) > 0;
break;
} else {
......@@ -75,8 +75,8 @@ export class SegmentIterator<T extends number = number> implements Iterator<Segs
const segmentEnd = this.segments[this.segmentMin + 1];
// TODO: add optimized version for interval and array?
const setEnd = OrderedSet.findPredecessorIndexInInterval(this.set, segmentEnd, this.setRange);
this.value.start = Interval.start(this.setRange) as T;
this.value.end = setEnd as T;
this.value.start = Interval.start(this.setRange);
this.value.end = setEnd;
this.setRange = Interval.ofBounds(setEnd, Interval.end(this.setRange));
return setEnd > this.value.start;
}
......@@ -94,7 +94,7 @@ export class SegmentIterator<T extends number = number> implements Iterator<Segs
this.hasNext = this.segmentMax >= this.segmentMin;
}
setSegment(segment: Segs.Segment<T>) {
setSegment(segment: Segs.Segment<number>) {
this.setRange = Interval.ofBounds(segment.start, segment.end);
this.updateSegmentRange();
}
......
......@@ -9,7 +9,7 @@ import OrderedSet from './ordered-set'
import * as Impl from './impl/segmentation'
namespace Segmentation {
export interface Segment<T extends number = number, I extends number = number> { index: number, start: T, end: T }
export interface Segment<I extends number = number> { index: I, start: number, end: number }
export const create: <T extends number = number, I extends number = number>(segs: ArrayLike<T>) => Segmentation<T, I> = Impl.create as any;
export const ofOffsets: <T extends number = number, I extends number = number>(offsets: ArrayLike<T>, bounds: Interval) => Segmentation<T, I> = Impl.ofOffsets as any;
......@@ -19,7 +19,7 @@ namespace Segmentation {
export const projectValue: <T extends number = number, I extends number = number>(segs: Segmentation<T, I>, set: OrderedSet<T>, value: T) => Interval = Impl.projectValue as any;
// Segment iterator that mutates a single segment object to mark all the segments.
export const transientSegments: <T extends number = number, I extends number = number>(segs: Segmentation<T, I>, set: OrderedSet<T>, segment?: Segment<T>) => Impl.SegmentIterator<T> = Impl.segments as any;
export const transientSegments: <T extends number = number, I extends number = number>(segs: Segmentation<T, I>, set: OrderedSet<T>, segment?: Segment) => Impl.SegmentIterator<I> = Impl.segments as any;
}
interface Segmentation<T extends number = number, I extends number = number> {
......
......@@ -4,7 +4,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Unit, StructureElement, StructureProperties, ElementIndex } from 'mol-model/structure';
import { Unit, StructureElement, StructureProperties } from 'mol-model/structure';
import { Segmentation } from 'mol-data/int';
import { MoleculeType } from 'mol-model/structure/model/types';
import Iterator from 'mol-data/iterator';
......@@ -50,7 +50,7 @@ function getTraceName(l: StructureElement) {
return traceName
}
function setTraceElement(l: StructureElement, residueSegment: Segmentation.Segment<ElementIndex>) {
function setTraceElement(l: StructureElement, residueSegment: Segmentation.Segment) {
const elements = l.unit.elements
l.element = elements[residueSegment.start]
const traceName = getTraceName(l)
......@@ -97,9 +97,9 @@ const enum AtomicPolymerBackboneIteratorState { nextPolymer, firstResidue, nextR
export class AtomicPolymerBackboneIterator<T extends number = number> implements Iterator<PolymerBackbonePair> {
private value: PolymerBackbonePair
private polymerIt: SegmentIterator<ElementIndex>
private residueIt: SegmentIterator<ElementIndex>
private polymerSegment: Segmentation.Segment<ElementIndex>
private polymerIt: SegmentIterator
private residueIt: SegmentIterator
private polymerSegment: Segmentation.Segment
private state: AtomicPolymerBackboneIteratorState = AtomicPolymerBackboneIteratorState.nextPolymer
private pos: SymmetryOperator.CoordinateMapper
......@@ -161,8 +161,8 @@ const enum CoarsePolymerBackboneIteratorState { nextPolymer, firstElement, nextE
export class CoarsePolymerBackboneIterator<T extends number = number> implements Iterator<PolymerBackbonePair> {
private value: PolymerBackbonePair
private polymerIt: SegmentIterator<ElementIndex>
private polymerSegment: Segmentation.Segment<ElementIndex>
private polymerIt: SegmentIterator
private polymerSegment: Segmentation.Segment
private state: CoarsePolymerBackboneIteratorState = CoarsePolymerBackboneIteratorState.nextPolymer
private pos: SymmetryOperator.CoordinateMapper
private elementIndex: number
......@@ -268,8 +268,8 @@ function createPolymerTraceElement (unit: Unit) {
export class AtomicPolymerTraceIterator<T extends number = number> implements Iterator<PolymerTraceElement> {
private value: PolymerTraceElement
private polymerIt: SegmentIterator<ElementIndex>
private residueIt: SegmentIterator<ElementIndex>
private polymerIt: SegmentIterator
private residueIt: SegmentIterator
// private polymerSegment: Segmentation.Segment<Element>
// private state: AtomicPolymerTraceIteratorState = AtomicPolymerTraceIteratorState.nextPolymer
// private pos: SymmetryOperator.CoordinateMapper
......
/**
* Copyright (c) 2017-2018 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 } from 'mol-data/int';
import { CifWriter } from 'mol-io/writer/cif';
import { StructureElement, StructureProperties as P, Unit } from '../../../structure';
import { CifExportContext } from '../mmcif';
import CifField = CifWriter.Field
import CifCategory = CifWriter.Category
export function _pdbx_struct_mod_residue(ctx: CifExportContext): CifCategory {
const residues = getModifiedResidues(ctx);
return {
data: residues,
name: 'pdbx_struct_mod_residue',
fields: pdbx_struct_mod_residue_fields,
rowCount: residues.length
};
}
const pdbx_struct_mod_residue_fields: CifField<number, StructureElement[]>[] = [
CifField.index('id'),
CifField.str(`label_comp_id`, (i, xs) => P.residue.label_comp_id(xs[i])),
CifField.int(`label_seq_id`, (i, xs) => P.residue.label_seq_id(xs[i])),
CifField.str(`pdbx_PDB_ins_code`, (i, xs) => P.residue.pdbx_PDB_ins_code(xs[i])),
CifField.str(`label_asym_id`, (i, xs) => P.chain.label_asym_id(xs[i])),
CifField.str(`label_entity_id`, (i, xs) => P.chain.label_entity_id(xs[i])),
CifField.str(`auth_comp_id`, (i, xs) => P.residue.auth_comp_id(xs[i])),
CifField.int(`auth_seq_id`, (i, xs) => P.residue.auth_seq_id(xs[i])),
CifField.str(`auth_asym_id`, (i, xs) => P.chain.auth_asym_id(xs[i])),
CifField.str<number, StructureElement[]>('parent_comp_id', (i, xs) => xs[i].unit.model.properties.modifiedResidues.parentId.get(P.residue.label_comp_id(xs[i]))!),
CifField.str('details', (i, xs) => xs[i].unit.model.properties.modifiedResidues.details.get(P.residue.label_comp_id(xs[i]))!)
];
function getModifiedResidues({ model, structure }: CifExportContext): StructureElement[] {
const map = model.properties.modifiedResidues.parentId;
if (!map.size) return [];
const ret = [];
const prop = P.residue.label_comp_id;
const loc = StructureElement.create();
for (const unit of structure.units) {
if (!Unit.isAtomic(unit) || !unit.conformation.operator.isIdentity) continue;
const residues = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements);
loc.unit = unit;
while (residues.hasNext) {
const seg = residues.move();
loc.element = unit.elements[seg.start];
const name = prop(loc);
if (map.has(name)) {
ret[ret.length] = StructureElement.create(loc.unit, loc.element);
}
}
}
return ret;
}
\ No newline at end of file
......@@ -9,11 +9,9 @@ import { CifWriter } from 'mol-io/writer/cif';
import { SecondaryStructure } from '../../model/properties/seconday-structure';
import { StructureElement, Unit, StructureProperties as P } from '../../structure';
import { CifExportContext } from '../mmcif';
import CifField = CifWriter.Field
import CifCategory = CifWriter.Category
import { Column } from 'mol-data/db';
import { ElementIndex } from '../../model';
export function _struct_conf(ctx: CifExportContext): CifCategory {
const elements = findElements(ctx, 'helix');
......@@ -42,7 +40,7 @@ function compare_ssr(x: SSElement<SecondaryStructure.Sheet>, y: SSElement<Second
const struct_conf_fields: CifField[] = [
CifField.str<number, SSElement<SecondaryStructure.Helix>[]>('conf_type_id', (i, data) => data[i].element.type_id),
CifField.str<number, SSElement<SecondaryStructure.Helix>[]>('conf_type_id', (i, data, idx) => `${data[i].element.type_id}${idx + 1}`),
CifField.str<number, SSElement<SecondaryStructure.Helix>[]>('id', (i, data, idx) => `${data[i].element.type_id}${idx + 1}`),
...residueIdFields('beg_', e => e.start),
...residueIdFields('end_', e => e.end),
CifField.str<number, SSElement<SecondaryStructure.Helix>[]>('pdbx_PDB_helix_class', (i, data) => data[i].element.helix_class),
......@@ -53,8 +51,8 @@ const struct_conf_fields: CifField[] = [
];
const struct_sheet_range_fields: CifField[] = [
CifField.index('id'),
CifField.str<number, SSElement<SecondaryStructure.Sheet>[]>('sheet_id', (i, data) => data[i].element.sheet_id),
CifField.index('id'),
...residueIdFields('beg_', e => e.start),
...residueIdFields('end_', e => e.end),
CifField.str('symmetry', (i, data) => '', { valueKind: (i, d) => Column.ValueKind.Unknown })
......@@ -66,7 +64,7 @@ function residueIdFields(prefix: string, loc: (e: SSElement<any>) => StructureEl
CifField.int(`${prefix}label_seq_id`, (i, d) => P.residue.label_seq_id(loc(d[i]))),
CifField.str(`pdbx_${prefix}PDB_ins_code`, (i, d) => P.residue.pdbx_PDB_ins_code(loc(d[i]))),
CifField.str(`${prefix}label_asym_id`, (i, d) => P.chain.label_asym_id(loc(d[i]))),
CifField.str(`${prefix}_entity_id`, (i, d) => P.chain.label_entity_id(loc(d[i]))),
CifField.str(`${prefix}label_entity_id`, (i, d) => P.chain.label_entity_id(loc(d[i]))),
CifField.str(`${prefix}auth_comp_id`, (i, d) => P.residue.auth_comp_id(loc(d[i]))),
CifField.int(`${prefix}auth_seq_id`, (i, d) => P.residue.auth_seq_id(loc(d[i]))),
CifField.str(`${prefix}auth_asym_id`, (i, d) => P.chain.auth_asym_id(loc(d[i])))
......@@ -92,7 +90,7 @@ function findElements<T extends SecondaryStructure.Element>(ctx: CifExportContex
const segs = unit.model.atomicHierarchy.residueAtomSegments;
const residues = Segmentation.transientSegments(segs, unit.elements);
let current: Segmentation.Segment<ElementIndex>, move = true;
let current: Segmentation.Segment, move = true;
while (residues.hasNext) {
if (move) current = residues.move();
......
......@@ -18,6 +18,7 @@ export interface CifExportContext {
import CifCategory = CifWriter.Category
import { _struct_conf, _struct_sheet_range } from './categories/secondary-structure';
import { _pdbx_struct_mod_residue } from './categories/modified-residues';
function copy_mmCif_category(name: keyof mmCIF_Schema) {
return ({ model }: CifExportContext) => {
......@@ -57,6 +58,8 @@ const Categories = [
copy_mmCif_category('chem_comp'),
copy_mmCif_category('atom_sites'),
_pdbx_struct_mod_residue,
// Atoms
_atom_site
];
......
......@@ -70,17 +70,20 @@ function getNcsOperators(format: mmCIF_Format) {
}
return opers;
}
function getModifiedResidueNameMap(format: mmCIF_Format) {
function getModifiedResidueNameMap(format: mmCIF_Format): Model['properties']['modifiedResidues'] {
const data = format.data.pdbx_struct_mod_residue;
const map = new Map<string, string>();
const parentId = new Map<string, string>();
const details = new Map<string, string>();
const comp_id = data.label_comp_id.isDefined ? data.label_comp_id : data.auth_comp_id;
const parent_id = data.parent_comp_id;
const parent_id = data.parent_comp_id, details_data = data.details;
for (let i = 0; i < data._rowCount; i++) {
map.set(comp_id.value(i), parent_id.value(i));
const id = comp_id.value(i);
parentId.set(id, parent_id.value(i));
details.set(id, details_data.value(i));
}
return map;
return { parentId, details };
}
function getAsymIdSerialMap(format: mmCIF_Format) {
......@@ -132,7 +135,7 @@ function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, entities
? format.data.entry.id.value(0)
: format.data._name;
const modifiedResidueNameMap = getModifiedResidueNameMap(format);
const modifiedResidues = getModifiedResidueNameMap(format);
const asymIdSerialMap = getAsymIdSerialMap(format)
const chemicalComponentMap = getChemicalComponentMap(format)
......@@ -143,14 +146,14 @@ function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, entities
modelNum: atom_site.pdbx_PDB_model_num.value(0),
entities,
symmetry: getSymmetry(format),
sequence: getSequence(format.data, entities, atomic.hierarchy, modifiedResidueNameMap),
sequence: getSequence(format.data, entities, atomic.hierarchy, modifiedResidues.parentId),
atomicHierarchy: atomic.hierarchy,
atomicConformation: atomic.conformation,
coarseHierarchy: coarse.hierarchy,
coarseConformation: coarse.conformation,
properties: {
secondaryStructure: getSecondaryStructureMmCif(format.data, atomic.hierarchy),
modifiedResidueNameMap,
modifiedResidues,
asymIdSerialMap,
chemicalComponentMap
},
......@@ -163,7 +166,7 @@ function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, entities
function createModelIHM(format: mmCIF_Format, data: IHMData): Model {
const atomic = getAtomicHierarchyAndConformation(format, data.atom_site, data.entities);
const coarse = getIHMCoarse(data);
const modifiedResidueNameMap = getModifiedResidueNameMap(format);
const modifiedResidues = getModifiedResidueNameMap(format);
const asymIdSerialMap = getAsymIdSerialMap(format)
const chemicalComponentMap = getChemicalComponentMap(format)
......@@ -174,14 +177,14 @@ function createModelIHM(format: mmCIF_Format, data: IHMData): Model {
modelNum: data.model_id,
entities: data.entities,
symmetry: getSymmetry(format),
sequence: getSequence(format.data, data.entities, atomic.hierarchy, modifiedResidueNameMap),
sequence: getSequence(format.data, data.entities, atomic.hierarchy, modifiedResidues.parentId),
atomicHierarchy: atomic.hierarchy,
atomicConformation: atomic.conformation,
coarseHierarchy: coarse.hierarchy,
coarseConformation: coarse.conformation,
properties: {
secondaryStructure: getSecondaryStructureMmCif(format.data, atomic.hierarchy),
modifiedResidueNameMap,
modifiedResidues,
asymIdSerialMap,
chemicalComponentMap
},
......
......@@ -141,7 +141,7 @@ export namespace ComponentBond {
loc.unit = unit;
while (residues.hasNext) {
const seg = residues.move();
loc.element = seg.start;
loc.element = unit.elements[seg.start];
names.add(prop(loc));
}
}
......
......@@ -42,7 +42,10 @@ export interface Model extends Readonly<{
/** secondary structure provided by the input file */
readonly secondaryStructure: SecondaryStructure,
/** maps modified residue name to its parent */
readonly modifiedResidueNameMap: Map<string, string>,
readonly modifiedResidues: {
parentId: Map<string, string>,
details: Map<string, string>
},
/** maps asym id to unique serial number */
readonly asymIdSerialMap: Map<string, number>
/** maps residue name to `ChemicalComponent` data */
......
......@@ -7,7 +7,7 @@
import Query from './query'
import Selection from './selection'
import { StructureElement, Unit, StructureProperties as P } from '../structure'
import { OrderedSet, Segmentation } from 'mol-data/int'
import { Segmentation } from 'mol-data/int'
import { LinearGroupingBuilder } from './utils/builders';
export const all: Query.Provider = async (s, ctx) => Selection.Singletons(s, s);
......@@ -87,20 +87,20 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, elements);
while (chainsIt.hasNext) {
const chainSegment = chainsIt.move();
l.element = OrderedSet.getAt(elements, chainSegment.start);
l.element = elements[chainSegment.start];
// test entity and chain
if (!entityTest(l) || !chainTest(l)) continue;
residuesIt.setSegment(chainSegment);
while (residuesIt.hasNext) {
const residueSegment = residuesIt.move();
l.element = OrderedSet.getAt(elements, residueSegment.start);
l.element = elements[residueSegment.start];
// test residue
if (!residueTest(l)) continue;
for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
l.element = OrderedSet.getAt(elements, j);
l.element = elements[j];
if (atomTest(l)) {
builder.addElement(l.element);
}
......@@ -134,20 +134,20 @@ function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, group
const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, elements);
while (chainsIt.hasNext) {
const chainSegment = chainsIt.move();
l.element = OrderedSet.getAt(elements, chainSegment.start);
l.element = elements[chainSegment.start];
// test entity and chain
if (!entityTest(l) || !chainTest(l)) continue;
residuesIt.setSegment(chainSegment);
while (residuesIt.hasNext) {
const residueSegment = residuesIt.move();
l.element = OrderedSet.getAt(elements, residueSegment.start);
l.element = elements[residueSegment.start];
// test residue
if (!residueTest(l)) continue;
for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
l.element = OrderedSet.getAt(elements, j);
l.element = elements[j];
if (atomTest(l)) builder.add(groupBy(l), unit.id, l.element);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment