diff --git a/src/mol-io/writer/cif/encoder.ts b/src/mol-io/writer/cif/encoder.ts index 3e51663ac42e82effffa731e7b38529c42623d3a..05dcf0052bb191bb92370f30a54493c38ff76a79 100644 --- a/src/mol-io/writer/cif/encoder.ts +++ b/src/mol-io/writer/cif/encoder.ts @@ -21,9 +21,10 @@ 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 valueKind?: (key: Key, data: Data) => Column.ValueKind, defaultFormat?: Field.Format, - value(key: Key, data: Data): string | number + shouldInclude?: (data: Data) => boolean } export namespace Field { @@ -35,31 +36,31 @@ export namespace Field { typedArray?: ArrayEncoding.TypedArrayCtor } - export function getDigitCount(field: Field) { - if (field.defaultFormat && typeof field.defaultFormat.digitCount !== 'undefined') return Math.max(0, Math.min(field.defaultFormat.digitCount, 16)); - return 6; - } + 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?: { valueKind?: (k: K, d: D) => Column.ValueKind, encoder?: ArrayEncoder }): Field<K, D> { - return { name, type: Type.Str, value, valueKind: params && params.valueKind, defaultFormat: params && params.encoder ? { encoder: params.encoder } : void 0 }; + export function str<K, D = any>(name: string, value: (k: K, d: D) => 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?: { valueKind?: (k: K, d: D) => Column.ValueKind, encoder?: ArrayEncoder, typedArray?: ArrayEncoding.TypedArrayCtor }): Field<K, D> { + export function int<K, D = any>(name: string, value: (k: K, d: D) => number, params?: ParamsBase<K, D> & { typedArray?: ArrayEncoding.TypedArrayCtor }): Field<K, D> { return { name, type: Type.Int, value, valueKind: params && params.valueKind, - defaultFormat: params ? { encoder: params.encoder, typedArray: params.typedArray } : void 0 }; + defaultFormat: params ? { encoder: params.encoder, typedArray: params.typedArray } : void 0, + shouldInclude: params && params.shouldInclude + }; } - export function float<K, D = any>(name: string, value: (k: K, d: D) => number, params?: { valueKind?: (k: K, d: D) => Column.ValueKind, encoder?: ArrayEncoder, typedArray?: ArrayEncoding.TypedArrayCtor, digitCount?: number }): Field<K, D> { + 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> { return { name, type: Type.Float, value, valueKind: params && params.valueKind, - defaultFormat: params ? { encoder: params.encoder, typedArray: params.typedArray, digitCount: typeof params.digitCount !== 'undefined' ? params.digitCount : void 0 } : void 0 + defaultFormat: params ? { encoder: params.encoder, typedArray: params.typedArray, digitCount: typeof params.digitCount !== 'undefined' ? params.digitCount : void 0 } : void 0, + shouldInclude: params && params.shouldInclude }; } } diff --git a/src/mol-io/writer/cif/encoder/binary.ts b/src/mol-io/writer/cif/encoder/binary.ts index e10b86940a15efd63c6b0d00d1c046a185300fe0..564adbfd8059a37d877d6617be08e82ae48991e6 100644 --- a/src/mol-io/writer/cif/encoder/binary.ts +++ b/src/mol-io/writer/cif/encoder/binary.ts @@ -14,6 +14,7 @@ import { } from '../../../common/binary-cif' import { Field, Category, Encoder } from '../encoder' import Writer from '../../writer' +import { getIncludedFields } from './util'; export default class BinaryEncoder implements Encoder<Uint8Array> { private data: EncodedFile; @@ -57,12 +58,17 @@ export default class BinaryEncoder implements Encoder<Uint8Array> { const first = categories[0]!; const cat: EncodedCategory = { name: '_' + first.name, columns: [], rowCount: count }; const data = categories.map(c => ({ data: c.data, keys: () => c.keys ? c.keys() : Iterator.Range(0, c.rowCount - 1) })); - for (const f of first.fields) { + const fields = getIncludedFields(first); + + for (const f of fields) { if (!this.filter.includeField(first.name, f.name)) continue; const format = this.formatter.getFormat(first.name, f.name); cat.columns.push(encodeField(f, data, count, getArrayCtor(f, format), getEncoder(f, format))); } + // no columns included. + if (!cat.columns.length) return; + this.dataBlocks[this.dataBlocks.length - 1].categories.push(cat); } diff --git a/src/mol-io/writer/cif/encoder/text.ts b/src/mol-io/writer/cif/encoder/text.ts index 7352dbace857d189afe873ffd3677c8bf5c35e22..55ec8ec85db359d964f72526ba0813de77fe9be5 100644 --- a/src/mol-io/writer/cif/encoder/text.ts +++ b/src/mol-io/writer/cif/encoder/text.ts @@ -11,6 +11,7 @@ import { Column } from 'mol-data/db' import StringBuilder from 'mol-util/string-builder' import { Category, Field, Encoder } from '../encoder' import Writer from '../../writer' +import { getFieldDigitCount, getIncludedFields } from './util'; export default class TextEncoder implements Encoder<string> { private builder = StringBuilder.create(); @@ -102,13 +103,13 @@ function getFloatPrecisions(categoryName: string, fields: Field[], formatter: Ca for (const f of fields) { const format = formatter.getFormat(categoryName, f.name); if (format && typeof format.digitCount !== 'undefined') ret[ret.length] = f.type === Field.Type.Float ? Math.pow(10, Math.max(0, Math.min(format.digitCount, 15))) : 0; - else ret[ret.length] = f.type === Field.Type.Float ? Math.pow(10, Field.getDigitCount(f)) : 0; + else ret[ret.length] = f.type === Field.Type.Float ? Math.pow(10, getFieldDigitCount(f)) : 0; } return ret; } function writeCifSingleRecord(category: Category<any>, builder: StringBuilder, filter: Category.Filter, formatter: Category.Formatter) { - const fields = category.fields; + const fields = getIncludedFields(category); const data = category.data; let width = fields.reduce((w, f) => filter.includeField(category.name, f.name) ? Math.max(w, f.name.length) : 0, 0); @@ -134,8 +135,11 @@ function writeCifSingleRecord(category: Category<any>, builder: StringBuilder, f function writeCifLoop(categories: Category[], builder: StringBuilder, filter: Category.Filter, formatter: Category.Formatter) { const first = categories[0]; - const fields = filter === Category.DefaultFilter ? first.fields : first.fields.filter(f => filter.includeField(first.name, f.name)); + const fieldSource = getIncludedFields(first); + const fields = filter === Category.DefaultFilter ? fieldSource : fieldSource.filter(f => filter.includeField(first.name, f.name)); const fieldCount = fields.length; + if (fieldCount === 0) return; + const precisions = getFloatPrecisions(first.name, fields, formatter); writeLine(builder, 'loop_'); diff --git a/src/mol-io/writer/cif/encoder/util.ts b/src/mol-io/writer/cif/encoder/util.ts new file mode 100644 index 0000000000000000000000000000000000000000..af8b3369f61d11939cca26f24b3bae02a0de4a6a --- /dev/null +++ b/src/mol-io/writer/cif/encoder/util.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Field, Category } from '../encoder'; + +export function getFieldDigitCount(field: Field) { + if (field.defaultFormat && typeof field.defaultFormat.digitCount !== 'undefined') return Math.max(0, Math.min(field.defaultFormat.digitCount, 16)); + return 6; +} + +export function getIncludedFields(category: Category<any, any>) { + return category.fields.some(f => !!f.shouldInclude) + ? category.fields.filter(f => !f.shouldInclude || f.shouldInclude(category.data)) + : category.fields; +} \ No newline at end of file diff --git a/src/mol-math/geometry/symmetry-operator.ts b/src/mol-math/geometry/symmetry-operator.ts index 8f9cac24028275ce2a8882e3859e1bd8c8e63c87..2e9776d8dd50ad3a642d1a08266ae4ced996bed2 100644 --- a/src/mol-math/geometry/symmetry-operator.ts +++ b/src/mol-math/geometry/symmetry-operator.ts @@ -18,7 +18,7 @@ interface SymmetryOperator { } namespace SymmetryOperator { - export const DefaultName = 'identity' + export const DefaultName = '1_555' export const Default: SymmetryOperator = create(DefaultName, Mat4.identity()); const RotationEpsilon = 0.0001; diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index 0a522303c91d4d124a9260cbb0c2031fed8d6e75..ea699f649fe5e900813d315af5cad2717b39bbb5 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -47,7 +47,9 @@ const atom_site_fields: CifField<Element.Location>[] = [ CifField.str('auth_asym_id', P.chain.auth_asym_id), CifField.int('pdbx_PDB_model_num', P.unit.model_num, { encoder: E.deltaRLE }), - CifField.str('operator_name', P.unit.operator_name) + CifField.str<Element.Location, Structure>('operator_name', P.unit.operator_name, { + shouldInclude: structure => structure.units.some(u => !u.conformation.operator.isIdentity) + }) ]; function copy_mmCif_cat(name: keyof mmCIF_Schema) { @@ -66,7 +68,7 @@ function _entity({ model, structure }: Context): CifCategory { function _atom_site({ structure }: Context): CifCategory { return { - data: void 0, + data: structure, name: 'atom_site', fields: atom_site_fields, rowCount: structure.elementCount,