From 53c12b748c2fd06016222e5047f48800fa833a84 Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Thu, 5 Jul 2018 11:42:55 +0200 Subject: [PATCH] wip, mmCIF exporter --- src/mol-io/writer/cif/encoder.ts | 12 ++++++++---- src/mol-io/writer/cif/encoder/binary.ts | 2 +- src/mol-io/writer/cif/encoder/text.ts | 10 ++++++---- .../structure/export/categories/atom_site.ts | 2 +- src/mol-model/structure/export/mmcif.ts | 7 ++++++- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/mol-io/writer/cif/encoder.ts b/src/mol-io/writer/cif/encoder.ts index 05dcf0052..174ea0f89 100644 --- a/src/mol-io/writer/cif/encoder.ts +++ b/src/mol-io/writer/cif/encoder.ts @@ -21,7 +21,7 @@ import { ArrayEncoder, ArrayEncoding } from '../../common/binary-cif'; export interface Field<Key = any, Data = any> { name: string, type: Field.Type, - value(key: Key, data: Data): string | number + value(key: Key, data: Data, index: number): string | number valueKind?: (key: Key, data: Data) => Column.ValueKind, defaultFormat?: Field.Format, shouldInclude?: (data: Data) => boolean @@ -38,11 +38,11 @@ export namespace Field { export type ParamsBase<K, D> = { valueKind?: (k: K, d: D) => Column.ValueKind, encoder?: ArrayEncoder, shouldInclude?: (data: D) => boolean } - export function str<K, D = any>(name: string, value: (k: K, d: D) => string, params?: ParamsBase<K, D>): Field<K, D> { + export function str<K, D = any>(name: string, value: (k: K, d: D, index: number) => string, params?: ParamsBase<K, D>): Field<K, D> { return { name, type: Type.Str, value, valueKind: params && params.valueKind, defaultFormat: params && params.encoder ? { encoder: params.encoder } : void 0, shouldInclude: params && params.shouldInclude }; } - export function int<K, D = any>(name: string, value: (k: K, d: D) => number, params?: ParamsBase<K, D> & { typedArray?: ArrayEncoding.TypedArrayCtor }): Field<K, D> { + export function int<K, D = any>(name: string, value: (k: K, d: D, index: number) => number, params?: ParamsBase<K, D> & { typedArray?: ArrayEncoding.TypedArrayCtor }): Field<K, D> { return { name, type: Type.Int, @@ -53,7 +53,7 @@ export namespace Field { }; } - export function float<K, D = any>(name: string, value: (k: K, d: D) => number, params?: ParamsBase<K, D> & { typedArray?: ArrayEncoding.TypedArrayCtor, digitCount?: number }): Field<K, D> { + export function float<K, D = any>(name: string, value: (k: K, d: D, index: number) => number, params?: ParamsBase<K, D> & { typedArray?: ArrayEncoding.TypedArrayCtor, digitCount?: number }): Field<K, D> { return { name, type: Type.Float, @@ -63,6 +63,10 @@ export namespace Field { shouldInclude: params && params.shouldInclude }; } + + export function index(name: string) { + return int(name, (e, d, i) => i + 1, { typedArray: Int32Array, encoder: ArrayEncoding.by(ArrayEncoding.delta).and(ArrayEncoding.runLength).and(ArrayEncoding.integerPacking) }) + } } export interface Category<Key = any, Data = any> { diff --git a/src/mol-io/writer/cif/encoder/binary.ts b/src/mol-io/writer/cif/encoder/binary.ts index 564adbfd8..01e07965d 100644 --- a/src/mol-io/writer/cif/encoder/binary.ts +++ b/src/mol-io/writer/cif/encoder/binary.ts @@ -141,7 +141,7 @@ function encodeField(field: Field, data: { data: any, keys: () => Iterator<any> allPresent = false; } else { mask[offset] = Column.ValueKind.Present; - array[offset] = getter(key, d); + array[offset] = getter(key, d, offset); } offset++; } diff --git a/src/mol-io/writer/cif/encoder/text.ts b/src/mol-io/writer/cif/encoder/text.ts index 55ec8ec85..a19162728 100644 --- a/src/mol-io/writer/cif/encoder/text.ts +++ b/src/mol-io/writer/cif/encoder/text.ts @@ -73,14 +73,14 @@ export default class TextEncoder implements Encoder<string> { } } -function writeValue(builder: StringBuilder, data: any, key: any, f: Field<any, any>, floatPrecision: number): boolean { +function writeValue(builder: StringBuilder, data: any, key: any, f: Field<any, any>, floatPrecision: number, index: number): boolean { const kind = f.valueKind; const p = kind ? kind(key, data) : Column.ValueKind.Present; if (p !== Column.ValueKind.Present) { if (p === Column.ValueKind.NotPresent) writeNotPresent(builder); else writeUnknown(builder); } else { - const val = f.value(key, data); + const val = f.value(key, data, index); const t = f.type; if (t === Field.Type.Str) { if (isMultiline(val as string)) { @@ -127,7 +127,7 @@ function writeCifSingleRecord(category: Category<any>, builder: StringBuilder, f if (!filter.includeField(category.name, f.name)) continue; StringBuilder.writePadRight(builder, `_${category.name}.${f.name}`, width); - const multiline = writeValue(builder, data, key, f, precisions[_f]); + const multiline = writeValue(builder, data, key, f, precisions[_f], 0); if (!multiline) StringBuilder.newline(builder); } StringBuilder.write(builder, '#\n'); @@ -147,6 +147,7 @@ function writeCifLoop(categories: Category[], builder: StringBuilder, filter: Ca writeLine(builder, `_${first.name}.${fields[i].name}`); } + let index = 0; for (let _c = 0; _c < categories.length; _c++) { const category = categories[_c]; const data = category.data; @@ -159,9 +160,10 @@ function writeCifLoop(categories: Category[], builder: StringBuilder, filter: Ca let multiline = false; for (let _f = 0; _f < fieldCount; _f++) { - multiline = writeValue(builder, data, key, fields[_f], precisions[_f]); + multiline = writeValue(builder, data, key, fields[_f], precisions[_f], index); } if (!multiline) StringBuilder.newline(builder); + index++; } } StringBuilder.write(builder, '#\n'); diff --git a/src/mol-model/structure/export/categories/atom_site.ts b/src/mol-model/structure/export/categories/atom_site.ts index 7ee771645..c5b1fab70 100644 --- a/src/mol-model/structure/export/categories/atom_site.ts +++ b/src/mol-model/structure/export/categories/atom_site.ts @@ -14,7 +14,7 @@ import E = CifWriter.Encodings const atom_site_fields: CifField<Element.Location>[] = [ CifField.str('group_PDB', P.residue.group_PDB), - CifField.int('id', P.atom.id, { encoder: E.deltaRLE }), + CifField.index('id'), CifField.str('type_symbol', P.atom.type_symbol as any), CifField.str('label_atom_id', P.atom.label_atom_id), CifField.str('label_alt_id', P.atom.label_alt_id), diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index eca4f961e..3a5f900c8 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -35,10 +35,15 @@ function _entity({ model, structure }: CifExportContext): CifCategory { const Categories = [ copy_mmCif_category('entry'), copy_mmCif_category('exptl'), + _entity, copy_mmCif_category('cell'), copy_mmCif_category('symmetry'), + copy_mmCif_category('pdbx_struct_assembly'), + copy_mmCif_category('pdbx_struct_assembly_gen'), + copy_mmCif_category('pdbx_struct_oper_list'), + // TODO: filter for actual present residues? copy_mmCif_category('chem_comp'), - _entity, + copy_mmCif_category('atom_sites'), _atom_site ]; -- GitLab