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

mmCIF secondary structure export

parent dc59cb88
No related branches found
No related tags found
No related merge requests found
...@@ -3,3 +3,118 @@ ...@@ -3,3 +3,118 @@
* *
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import { Segmentation } from 'mol-data/int';
import { CifWriter } from 'mol-io/writer/cif';
import { SecondaryStructure } from '../../model/properties/seconday-structure';
import { Element, Unit, StructureProperties as P } from '../../structure';
import { CifExportContext } from '../mmcif';
import CifField = CifWriter.Field
import CifCategory = CifWriter.Category
import { Column } from 'mol-data/db';
export function _struct_conf(ctx: CifExportContext): CifCategory {
const elements = findElements(ctx, 'helix');
return {
data: elements,
name: 'struct_conf',
fields: struct_conf_fields,
rowCount: elements.length
};
}
export function _struct_sheet_range(ctx: CifExportContext): CifCategory {
const elements = findElements(ctx, 'sheet');
return {
data: elements,
name: 'struct_sheet_range',
fields: struct_sheet_range_fields,
rowCount: elements.length
};
}
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}`),
...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),
CifField.str<number, SSElement<SecondaryStructure.Helix>[]>('details', (i, data) => data[i].element.details || '', {
valueKind: (i, d) => !!d[i].element.details ? Column.ValueKind.Present : Column.ValueKind.Unknown
}),
CifField.int<number, SSElement<SecondaryStructure.Helix>[]>('pdbx_PDB_helix_class', (i, data) => data[i].length)
];
const struct_sheet_range_fields: CifField[] = [
CifField.index('id'),
CifField.str<number, SSElement<SecondaryStructure.Sheet>[]>('sheet_id', (i, data) => data[i].element.sheet_id),
...residueIdFields('beg_', e => e.start),
...residueIdFields('end_', e => e.end),
CifField.str('symmetry', (i, data) => '', { valueKind: (i, d) => Column.ValueKind.Unknown })
];
function residueIdFields(prefix: string, loc: (e: SSElement<any>) => Element.Location): CifField<number, SSElement<SecondaryStructure.Helix>[]>[] {
return [
CifField.str(`${prefix}label_comp_id`, (i, d) => P.residue.label_comp_id(loc(d[i]))),
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}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])))
];
}
interface SSElement<T extends SecondaryStructure.Element> {
start: Element.Location,
end: Element.Location,
length: number,
element: T
}
function findElements<T extends SecondaryStructure.Element>(ctx: CifExportContext, kind: SecondaryStructure.Element['kind']) {
const { index, elements } = ctx.model.properties.secondaryStructure;
const ssElements: SSElement<any>[] = [];
for (const unit of ctx.structure.units) {
// currently can only support this for "identity" operators.
if (!Unit.isAtomic(unit) || !unit.conformation.operator.isIdentity) continue;
const segs = unit.model.atomicHierarchy.residueSegments;
const residues = Segmentation.transientSegments(segs, unit.elements);
let current: Segmentation.Segment<Element>, move = true;
while (residues.hasNext) {
if (move) current = residues.move();
const start = current!.index;
const startIdx = index[start];
const element = elements[startIdx];
if (element.kind !== kind) {
move = true;
continue;
}
let prev = start;
while (residues.hasNext) {
prev = current!.index;
current = residues.move();
if (startIdx !== index[current.index]) {
move = false;
ssElements[ssElements.length] = {
start: Element.Location(unit, segs.segments[start]),
end: Element.Location(unit, segs.segments[prev]),
length: prev - start + 1,
element
}
break;
}
}
}
}
return ssElements as SSElement<T>[];
}
\ No newline at end of file
...@@ -17,6 +17,7 @@ export interface CifExportContext { ...@@ -17,6 +17,7 @@ export interface CifExportContext {
} }
import CifCategory = CifWriter.Category import CifCategory = CifWriter.Category
import { _struct_conf, _struct_sheet_range } from './categories/secondary-structure';
function copy_mmCif_category(name: keyof mmCIF_Schema) { function copy_mmCif_category(name: keyof mmCIF_Schema) {
return ({ model }: CifExportContext) => { return ({ model }: CifExportContext) => {
...@@ -48,7 +49,8 @@ const Categories = [ ...@@ -48,7 +49,8 @@ const Categories = [
copy_mmCif_category('pdbx_struct_oper_list'), copy_mmCif_category('pdbx_struct_oper_list'),
// Secondary structure // Secondary structure
// TODO _struct_conf,
_struct_sheet_range,
// Misc // Misc
// TODO: filter for actual present residues? // TODO: filter for actual present residues?
......
...@@ -56,9 +56,7 @@ function addHelices(cat: mmCIF['struct_conf'], map: SecondaryStructureMap, eleme ...@@ -56,9 +56,7 @@ function addHelices(cat: mmCIF['struct_conf'], map: SecondaryStructureMap, eleme
const element: SecondaryStructure.Helix = { const element: SecondaryStructure.Helix = {
kind: 'helix', kind: 'helix',
flags: type, flags: type,
type_id: pdbx_PDB_helix_class.valueKind(i) === Column.ValueKind.Present type_id: conf_type_id.valueKind(i) === Column.ValueKind.Present ? conf_type_id.value(i) : 'HELIX_P',
? pdbx_PDB_helix_class.value(i) : conf_type_id.valueKind(i) === Column.ValueKind.Present
? conf_type_id.value(i) : 'HELIX_P',
helix_class: pdbx_PDB_helix_class.value(i), helix_class: pdbx_PDB_helix_class.value(i),
details: details.valueKind(i) === Column.ValueKind.Present ? details.value(i) : void 0 details: details.valueKind(i) === Column.ValueKind.Present ? details.value(i) : void 0
}; };
......
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