diff --git a/src/mol-io/writer/cif.ts b/src/mol-io/writer/cif.ts index 8c6665fedb80a6f15aa5e1f2f5d3f32bf7e2f36e..772ff6aeabb129736b16677195736695a1e9ffe3 100644 --- a/src/mol-io/writer/cif.ts +++ b/src/mol-io/writer/cif.ts @@ -21,6 +21,10 @@ export namespace CifWriter { return binary ? new BinaryEncoder(encoderName) : new TextEncoder(); } + export function fields<K = number, D = any>() { + return Field.build<K, D>(); + } + import E = Encoding export const Encodings = { deltaRLE: E.by(E.delta).and(E.runLength).and(E.integerPacking), diff --git a/src/mol-io/writer/cif/encoder.ts b/src/mol-io/writer/cif/encoder.ts index 883f2aed440e97b3ec60ac62f72eff55d2e7e1a3..20681c04cb085a304aa0d0b6772bbd63bb488638 100644 --- a/src/mol-io/writer/cif/encoder.ts +++ b/src/mol-io/writer/cif/encoder.ts @@ -67,6 +67,36 @@ export namespace Field { 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 class Builder<K = number, D = any> { + private fields: Field<K, D>[] = []; + + index(name: string) { + this.fields.push(Field.index(name)); + return this; + } + + str(name: string, value: (k: K, d: D, index: number) => string, params?: ParamsBase<K, D>) { + this.fields.push(Field.str(name, value, params)); + return this; + } + + int(name: string, value: (k: K, d: D, index: number) => number, params?: ParamsBase<K, D> & { typedArray?: ArrayEncoding.TypedArrayCtor }) { + this.fields.push(Field.int(name, value, params)); + return this; + } + + float(name: string, value: (k: K, d: D, index: number) => number, params?: ParamsBase<K, D> & { typedArray?: ArrayEncoding.TypedArrayCtor, digitCount?: number }) { + this.fields.push(Field.float(name, value, params)); + return this; + } + + getFields() { return this.fields; } + } + + export function build<K = number, D = any>() { + return new Builder<K, D>(); + } } export interface Category<Ctx = any> { diff --git a/src/mol-model/structure/export/categories/atom_site.ts b/src/mol-model/structure/export/categories/atom_site.ts index 926ed369016843f1be44d3659958d36c839cbeb9..e80212e108ab054ce283ea14121692dae4d63c33 100644 --- a/src/mol-model/structure/export/categories/atom_site.ts +++ b/src/mol-model/structure/export/categories/atom_site.ts @@ -12,42 +12,42 @@ import CifField = CifWriter.Field import CifCategory = CifWriter.Category import E = CifWriter.Encodings -const atom_site_fields: CifField<StructureElement, Structure>[] = [ - CifField.str('group_PDB', P.residue.group_PDB), - CifField.index('id'), - CifField.str('type_symbol', P.atom.type_symbol as any), - CifField.str('label_atom_id', P.atom.label_atom_id), +const atom_site_fields = CifWriter.fields<StructureElement, Structure>() + .str('group_PDB', P.residue.group_PDB) + .index('id') + .str('type_symbol', P.atom.type_symbol as any) + .str('label_atom_id', P.atom.label_atom_id) - CifField.str('label_comp_id', P.residue.label_comp_id), - CifField.int('label_seq_id', P.residue.label_seq_id, { + .str('label_comp_id', P.residue.label_comp_id) + .int('label_seq_id', P.residue.label_seq_id, { encoder: E.deltaRLE, valueKind: (k, d) => { const m = k.unit.model; return m.atomicHierarchy.residues.label_seq_id.valueKind(m.atomicHierarchy.residueAtomSegments.index[k.element]); } - }), - CifField.str('label_alt_id', P.atom.label_alt_id), - CifField.str('pdbx_PDB_ins_code', P.residue.pdbx_PDB_ins_code), + }) + .str('label_alt_id', P.atom.label_alt_id) + .str('pdbx_PDB_ins_code', P.residue.pdbx_PDB_ins_code) - CifField.str('label_asym_id', P.chain.label_asym_id), - CifField.str('label_entity_id', P.chain.label_entity_id), + .str('label_asym_id', P.chain.label_asym_id) + .str('label_entity_id', P.chain.label_entity_id) - CifField.float('Cartn_x', P.atom.x, { digitCount: 3, encoder: E.fixedPoint3 }), - CifField.float('Cartn_y', P.atom.y, { digitCount: 3, encoder: E.fixedPoint3 }), - CifField.float('Cartn_z', P.atom.z, { digitCount: 3, encoder: E.fixedPoint3 }), - CifField.float('occupancy', P.atom.occupancy, { digitCount: 2, encoder: E.fixedPoint2 }), - CifField.int('pdbx_formal_charge', P.atom.pdbx_formal_charge, { encoder: E.deltaRLE }), + .float('Cartn_x', P.atom.x, { digitCount: 3, encoder: E.fixedPoint3 }) + .float('Cartn_y', P.atom.y, { digitCount: 3, encoder: E.fixedPoint3 }) + .float('Cartn_z', P.atom.z, { digitCount: 3, encoder: E.fixedPoint3 }) + .float('occupancy', P.atom.occupancy, { digitCount: 2, encoder: E.fixedPoint2 }) + .int('pdbx_formal_charge', P.atom.pdbx_formal_charge, { encoder: E.deltaRLE }) - CifField.str('auth_atom_id', P.atom.auth_atom_id), - CifField.str('auth_comp_id', P.residue.auth_comp_id), - CifField.int('auth_seq_id', P.residue.auth_seq_id, { encoder: E.deltaRLE }), - CifField.str('auth_asym_id', P.chain.auth_asym_id), + .str('auth_atom_id', P.atom.auth_atom_id) + .str('auth_comp_id', P.residue.auth_comp_id) + .int('auth_seq_id', P.residue.auth_seq_id, { encoder: E.deltaRLE }) + .str('auth_asym_id', P.chain.auth_asym_id) - CifField.int('pdbx_PDB_model_num', P.unit.model_num, { encoder: E.deltaRLE }), - CifField.str<StructureElement, Structure>('operator_name', P.unit.operator_name, { + .int('pdbx_PDB_model_num', P.unit.model_num, { encoder: E.deltaRLE }) + .str('operator_name', P.unit.operator_name, { shouldInclude: structure => structure.units.some(u => !u.conformation.operator.isIdentity) }) -]; + .getFields(); export const _atom_site: CifCategory<CifExportContext> = { name: 'atom_site', @@ -70,31 +70,31 @@ function mappedProp<K, D>(loc: (key: K, data: D) => StructureElement, prop: (e: } export function residueIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, prefix = ''): CifField<K, D>[] { - return [ - CifField.str(prefixed(prefix, `label_comp_id`), mappedProp(getLocation, P.residue.label_comp_id)), - CifField.int(prefixed(prefix, `label_seq_id`), mappedProp(getLocation, P.residue.label_seq_id), { + return CifWriter.fields<K, D>() + .str(prefixed(prefix, `label_comp_id`), mappedProp(getLocation, P.residue.label_comp_id)) + .int(prefixed(prefix, `label_seq_id`), mappedProp(getLocation, P.residue.label_seq_id), { encoder: E.deltaRLE, valueKind: (k, d) => { const e = getLocation(k, d); const m = e.unit.model; return m.atomicHierarchy.residues.label_seq_id.valueKind(m.atomicHierarchy.residueAtomSegments.index[e.element]); } - }), - CifField.str(prefixed(prefix, `pdbx_PDB_ins_code`), mappedProp(getLocation, P.residue.pdbx_PDB_ins_code)), + }) + .str(prefixed(prefix, `pdbx_PDB_ins_code`), mappedProp(getLocation, P.residue.pdbx_PDB_ins_code)) - CifField.str(prefixed(prefix, `label_asym_id`), mappedProp(getLocation, P.chain.label_asym_id)), - CifField.str(prefixed(prefix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id)), + .str(prefixed(prefix, `label_asym_id`), mappedProp(getLocation, P.chain.label_asym_id)) + .str(prefixed(prefix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id)) - CifField.str(prefixed(prefix, `auth_comp_id`), mappedProp(getLocation, P.residue.auth_comp_id)), - CifField.int(prefixed(prefix, `auth_seq_id`), mappedProp(getLocation, P.residue.auth_seq_id), { encoder: E.deltaRLE }), - CifField.str(prefixed(prefix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id)) - ]; + .str(prefixed(prefix, `auth_comp_id`), mappedProp(getLocation, P.residue.auth_comp_id)) + .int(prefixed(prefix, `auth_seq_id`), mappedProp(getLocation, P.residue.auth_seq_id), { encoder: E.deltaRLE }) + .str(prefixed(prefix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id)) + .getFields(); } export function chainIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, prefix = ''): CifField<K, D>[] { - return [ - CifField.str(prefixed(prefix, `label_asym_id`), mappedProp(getLocation, P.chain.label_asym_id)), - CifField.str(prefixed(prefix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id)), - CifField.str(prefixed(prefix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id)) - ]; + return CifField.build<K, D>() + .str(prefixed(prefix, `label_asym_id`), mappedProp(getLocation, P.chain.label_asym_id)) + .str(prefixed(prefix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id)) + .str(prefixed(prefix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id)) + .getFields(); } \ No newline at end of file