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

More CIF writer refactoring

parent 3b8adde5
Branches
Tags
No related merge requests found
......@@ -5,7 +5,7 @@
*/
import CIF, { CifCategory } from 'mol-io/reader/cif'
import { CIFCategory, createCIFEncoder } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
import * as fs from 'fs'
import classify from './field-classifier'
......@@ -18,7 +18,7 @@ async function getCIF(path: string) {
return parsed.result;
}
function getCategoryInstanceProvider(cat: CifCategory): CIFCategory.Provider {
function getCategoryInstanceProvider(cat: CifCategory): CifWriter.Category.Provider {
return function (ctx: any) {
return {
data: cat,
......@@ -32,7 +32,7 @@ function getCategoryInstanceProvider(cat: CifCategory): CIFCategory.Provider {
export default async function convert(path: string, asText = false) {
const cif = await getCIF(path);
const encoder = createCIFEncoder({ binary: !asText, encoderName: 'mol* cif2bcif' });
const encoder = CifWriter.createEncoder({ binary: !asText, encoderName: 'mol* cif2bcif' });
for (const b of cif.blocks) {
encoder.startDataBlock(b.header);
for (const c of b.categoryNames) {
......
......@@ -6,14 +6,14 @@
import { Column } from 'mol-data/db'
import { CifField } from 'mol-io/reader/cif/data-model'
import { CIFField } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
const intRegex = /^-?\d+$/
const floatRegex = /^-?(([0-9]+)[.]?|([0-9]*[.][0-9]+))([(][0-9]+[)])?([eE][+-]?[0-9]+)?/
// Classify a cif field as str, int or float based the data it contains.
// To classify a field as int or float all items are checked.
function classify(name: string, field: CifField): CIFField {
function classify(name: string, field: CifField): CifWriter.Field {
let floatCount = 0, hasString = false;
for (let i = 0, _i = field.rowCount; i < _i; i++) {
const k = field.valueKind(i);
......@@ -24,9 +24,9 @@ function classify(name: string, field: CifField): CIFField {
else { hasString = true; break; }
}
if (hasString) return { name, type: CIFField.Type.Str, value: field.str, valueKind: field.valueKind };
if (floatCount > 0) return { name, type: CIFField.Type.Float, value: field.float, valueKind: field.valueKind };
return { name, type: CIFField.Type.Int, value: field.int, valueKind: field.valueKind };
if (hasString) return { name, type: CifWriter.Field.Type.Str, value: field.str, valueKind: field.valueKind };
if (floatCount > 0) return { name, type: CifWriter.Field.Type.Float, value: field.float, valueKind: field.valueKind };
return { name, type: CifWriter.Field.Type.Int, value: field.int, valueKind: field.valueKind };
}
export default classify;
\ No newline at end of file
......@@ -17,7 +17,7 @@ import { Progress } from 'mol-task'
import { Database, Table, DatabaseCollection } from 'mol-data/db'
import CIF from 'mol-io/reader/cif'
// import { CCD_Schema } from 'mol-io/reader/cif/schema/ccd'
import { CIFEncoder, createCIFEncoder } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
import { mmCIF_Schema, mmCIF_Database } from 'mol-io/reader/cif/schema/mmcif';
import { CCD_Schema } from 'mol-io/reader/cif/schema/ccd';
import { BIRD_Schema } from 'mol-io/reader/cif/schema/bird';
......@@ -85,8 +85,8 @@ async function parseCif(data: string|Uint8Array) {
}
export function getEncodedCif(name: string, database: Database<Database.Schema>, binary = false) {
const encoder = createCIFEncoder({ binary, encoderName: 'mol*' });
CIFEncoder.writeDatabase(encoder, name, database)
const encoder = CifWriter.createEncoder({ binary, encoderName: 'mol*' });
CifWriter.Encoder.writeDatabase(encoder, name, database)
return encoder.getData();
}
......
......@@ -5,13 +5,13 @@
*/
import { Table } from 'mol-data/db'
import { CIFEncoder, createCIFEncoder as createEncoder } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
import * as S from './schemas'
import { getCategoryInstanceProvider } from './utils'
export default function create(allData: any) {
const mols = Object.keys(allData);
const enc = createEncoder();
const enc = CifWriter.createEncoder();
enc.startDataBlock(mols[0]);
if (!mols.length) return enc.getData();
......@@ -36,7 +36,7 @@ interface DomainAnnotation {
}
type MappingRow = Table.Row<S.mapping>;
function writeDomain(enc: CIFEncoder, domain: DomainAnnotation | undefined) {
function writeDomain(enc: CifWriter.Encoder, domain: DomainAnnotation | undefined) {
if (!domain) return;
enc.writeCategory(getCategoryInstanceProvider(`pdbx_${domain.name}_domain_annotation`, domain.domains));
enc.writeCategory(getCategoryInstanceProvider(`pdbx_${domain.name}_domain_mapping`, domain.mappings));
......
......@@ -5,7 +5,7 @@
*/
import { Table } from 'mol-data/db'
import { CIFField, CIFCategory } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
function columnValue(k: string) {
return (i: number, d: any) => d[k].value(i);
......@@ -16,16 +16,16 @@ function columnValueKind(k: string) {
}
function ofSchema(schema: Table.Schema) {
const fields: CIFField[] = [];
const fields: CifWriter.Field[] = [];
for (const k of Object.keys(schema)) {
const t = schema[k];
const type: any = t.valueType === 'str' ? CIFField.Type.Str : t.valueType === 'int' ? CIFField.Type.Int : CIFField.Type.Float;
const type: any = t.valueType === 'str' ? CifWriter.Field.Type.Str : t.valueType === 'int' ? CifWriter.Field.Type.Int : CifWriter.Field.Type.Float;
fields.push({ name: k, type, value: columnValue(k), valueKind: columnValueKind(k) })
}
return fields;
}
export function getCategoryInstanceProvider(name: string, table: Table<any>): CIFCategory.Provider {
export function getCategoryInstanceProvider(name: string, table: Table<any>): CifWriter.Category.Provider {
return () => {
return {
data: table,
......
......@@ -7,11 +7,22 @@
import TextCIFEncoder from './cif/encoder/text'
import BinaryCIFEncoder from './cif/encoder/binary'
import { CIFEncoder } from './cif/encoder'
import * as _Encoder from './cif/encoder'
export * from './cif/encoder'
// export * from './cif/encoder'
export function createCIFEncoder(params?: { binary?: boolean, encoderName?: string }): CIFEncoder {
// export function createCIFEncoder(params?: { binary?: boolean, encoderName?: string }): CIFEncoder {
// const { binary = false, encoderName = 'mol*' } = params || {};
// return binary ? new BinaryCIFEncoder(encoderName) : new TextCIFEncoder();
//}
export namespace CifWriter {
export import Encoder = _Encoder.CIFEncoder
export import Category = _Encoder.CIFCategory
export import Field = _Encoder.CIFField
export function createEncoder(params?: { binary?: boolean, encoderName?: string }): Encoder {
const { binary = false, encoderName = 'mol*' } = params || {};
return binary ? new BinaryCIFEncoder(encoderName) : new TextCIFEncoder();
}
}
\ No newline at end of file
......@@ -5,7 +5,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { CIFEncoder, createCIFEncoder, CIFCategory, CIFField } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
// import { mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'
import { Structure, Element } from '../structure'
import { Model } from '../model'
......@@ -16,40 +16,43 @@ interface Context {
model: Model
}
const atom_site_fields: CIFField<Element.Location>[] = [
CIFField.str('group_PDB', P.residue.group_PDB),
CIFField.int('id', P.atom.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),
import CifField = CifWriter.Field
import CifCategory = CifWriter.Category
CIFField.str('label_comp_id', P.residue.label_comp_id),
CIFField.int('label_seq_id', P.residue.label_seq_id),
CIFField.str('pdbx_PDB_ins_code', P.residue.pdbx_PDB_ins_code),
const atom_site_fields: CifField<Element.Location>[] = [
CifField.str('group_PDB', P.residue.group_PDB),
CifField.int('id', P.atom.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),
CIFField.str('label_asym_id', P.chain.label_asym_id),
CIFField.str('label_entity_id', P.chain.label_entity_id),
CifField.str('label_comp_id', P.residue.label_comp_id),
CifField.int('label_seq_id', P.residue.label_seq_id),
CifField.str('pdbx_PDB_ins_code', P.residue.pdbx_PDB_ins_code),
CIFField.float('Cartn_x', P.atom.x),
CIFField.float('Cartn_y', P.atom.y),
CIFField.float('Cartn_z', P.atom.z),
CIFField.float('occupancy', P.atom.occupancy),
CIFField.int('pdbx_formal_charge', P.atom.pdbx_formal_charge),
CifField.str('label_asym_id', P.chain.label_asym_id),
CifField.str('label_entity_id', P.chain.label_entity_id),
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),
CIFField.str('auth_asym_id', P.chain.auth_asym_id),
CifField.float('Cartn_x', P.atom.x),
CifField.float('Cartn_y', P.atom.y),
CifField.float('Cartn_z', P.atom.z),
CifField.float('occupancy', P.atom.occupancy),
CifField.int('pdbx_formal_charge', P.atom.pdbx_formal_charge),
CIFField.int('pdbx_PDB_model_num', P.unit.model_num),
CIFField.str('operator_name', P.unit.operator_name)
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),
CifField.str('auth_asym_id', P.chain.auth_asym_id),
CifField.int('pdbx_PDB_model_num', P.unit.model_num),
CifField.str('operator_name', P.unit.operator_name)
];
function entityProvider({ model }: Context): CIFCategory {
return CIFCategory.ofTable('entity', model.entities.data);
function entityProvider({ model }: Context): CifCategory {
return CifCategory.ofTable('entity', model.entities.data);
}
function atomSiteProvider({ structure }: Context): CIFCategory {
function atomSiteProvider({ structure }: Context): CifCategory {
return {
data: void 0,
name: 'atom_site',
......@@ -60,7 +63,7 @@ function atomSiteProvider({ structure }: Context): CIFCategory {
}
/** Doesn't start a data block */
export function encode_mmCIF_categories(encoder: CIFEncoder, structure: Structure) {
export function encode_mmCIF_categories(encoder: CifWriter.Encoder, structure: Structure) {
const models = Structure.getModels(structure);
if (models.length !== 1) throw 'Can\'t export stucture composed from multiple models.';
const model = models[0];
......@@ -71,10 +74,10 @@ export function encode_mmCIF_categories(encoder: CIFEncoder, structure: Structur
}
function to_mmCIF(name: string, structure: Structure, asBinary = false) {
const w = createCIFEncoder({ binary: asBinary });
w.startDataBlock(name);
encode_mmCIF_categories(w, structure);
return w.getData();
const enc = CifWriter.createEncoder({ binary: asBinary });
enc.startDataBlock(name);
encode_mmCIF_categories(enc, structure);
return enc.getData();
}
export default to_mmCIF
\ No newline at end of file
......@@ -4,21 +4,21 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { CIFCategory, CIFField, createCIFEncoder } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
const category1fields: CIFField[] = [
CIFField.str('f1', i => 'v' + i),
CIFField.int('f2', i => i * i),
CIFField.float('f3', i => Math.random()),
const category1fields: CifWriter.Field[] = [
CifWriter.Field.str('f1', i => 'v' + i),
CifWriter.Field.int('f2', i => i * i),
CifWriter.Field.float('f3', i => Math.random()),
];
const category2fields: CIFField[] = [
CIFField.str('e1', i => 'v\n' + i),
CIFField.int('e2', i => i * i),
CIFField.float('e3', i => Math.random()),
const category2fields: CifWriter.Field[] = [
CifWriter.Field.str('e1', i => 'v\n' + i),
CifWriter.Field.int('e2', i => i * i),
CifWriter.Field.float('e3', i => Math.random()),
];
function getInstance(ctx: { name: string, fields: CIFField[], rowCount: number }): CIFCategory {
function getInstance(ctx: { name: string, fields: CifWriter.Field[], rowCount: number }): CifWriter.Category {
return {
data: void 0,
name: ctx.name,
......@@ -27,9 +27,9 @@ function getInstance(ctx: { name: string, fields: CIFField[], rowCount: number }
}
}
const w = createCIFEncoder();
const enc = CifWriter.createEncoder();
w.startDataBlock('test');
w.writeCategory(getInstance, [{ rowCount: 5, name: 'cat1', fields: category1fields }]);
w.writeCategory(getInstance, [{ rowCount: 1, name: 'cat2', fields: category2fields }]);
console.log(w.getData());
enc.startDataBlock('test');
enc.writeCategory(getInstance, [{ rowCount: 5, name: 'cat1', fields: category1fields }]);
enc.writeCategory(getInstance, [{ rowCount: 1, name: 'cat2', fields: category2fields }]);
console.log(enc.getData());
......@@ -11,7 +11,7 @@ import Config from '../config';
import { Progress, now } from 'mol-task';
import { ConsoleLogger } from 'mol-util/console-logger';
import Writer from 'mol-io/writer/writer';
import { CIFCategory, CIFField, createCIFEncoder } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
import { encode_mmCIF_categories } from 'mol-model/structure/export/mmcif';
import { Selection } from 'mol-model/structure';
import Version from '../version'
......@@ -74,7 +74,7 @@ export async function resolveRequest(req: Request, writer: Writer) {
ConsoleLogger.logId(req.id, 'Query', 'Query finished.');
const encoder = createCIFEncoder({ binary: req.responseFormat.isBinary, encoderName: `ModelServer ${Version}` });
const encoder = CifWriter.createEncoder({ binary: req.responseFormat.isBinary, encoderName: `ModelServer ${Version}` });
perf.start('encode');
encoder.startDataBlock('result');
......@@ -105,18 +105,20 @@ export function abortingObserver(p: Progress) {
}
}
function string<T>(name: string, str: (data: T, i: number) => string, isSpecified?: (data: T) => boolean): CIFField<number, T> {
import CifField = CifWriter.Field
function string<T>(name: string, str: (data: T, i: number) => string, isSpecified?: (data: T) => boolean): CifField<number, T> {
if (isSpecified) {
return CIFField.str(name, (i, d) => str(d, i), { valueKind: (i, d) => isSpecified(d) ? Column.ValueKind.Present : Column.ValueKind.NotPresent });
return CifField.str(name, (i, d) => str(d, i), { valueKind: (i, d) => isSpecified(d) ? Column.ValueKind.Present : Column.ValueKind.NotPresent });
}
return CIFField.str(name, (i, d) => str(d, i));
return CifField.str(name, (i, d) => str(d, i));
}
function int32<T>(name: string, value: (data: T) => number): CIFField<number, T> {
return CIFField.int(name, (i, d) => value(d));
function int32<T>(name: string, value: (data: T) => number): CifField<number, T> {
return CifField.int(name, (i, d) => value(d));
}
const _model_server_result_fields: CIFField<number, Request>[] = [
const _model_server_result_fields: CifField<number, Request>[] = [
string<Request>('request_id', ctx => '' + ctx.id),
string<Request>('datetime_utc', ctx => ctx.datetime_utc),
string<Request>('server_version', ctx => Version),
......@@ -125,12 +127,12 @@ const _model_server_result_fields: CIFField<number, Request>[] = [
string<Request>('entry_id', ctx => ctx.entryId),
];
const _model_server_params_fields: CIFField<number, string[]>[] = [
const _model_server_params_fields: CifField<number, string[]>[] = [
string<string[]>('name', (ctx, i) => ctx[i][0]),
string<string[]>('value', (ctx, i) => ctx[i][1])
];
const _model_server_stats_fields: CIFField<number, Stats>[] = [
const _model_server_stats_fields: CifField<number, Stats>[] = [
int32<Stats>('io_time_ms', ctx => ctx.structure.info.readTime | 0),
int32<Stats>('parse_time_ms', ctx => ctx.structure.info.parseTime | 0),
int32<Stats>('create_model_time_ms', ctx => ctx.structure.info.createModelTime | 0),
......@@ -139,7 +141,7 @@ const _model_server_stats_fields: CIFField<number, Stats>[] = [
];
function _model_server_result(request: Request): CIFCategory {
function _model_server_result(request: Request): CifWriter.Category {
return {
data: request,
name: 'model_server_result',
......@@ -148,7 +150,7 @@ function _model_server_result(request: Request): CIFCategory {
};
}
function _model_server_params(request: Request): CIFCategory {
function _model_server_params(request: Request): CifWriter.Category {
const params: string[][] = [];
for (const k of Object.keys(request.normalizedParams)) {
params.push([k, '' + request.normalizedParams[k]]);
......@@ -161,7 +163,7 @@ function _model_server_params(request: Request): CIFCategory {
};
}
function _model_server_stats(stats: Stats): CIFCategory {
function _model_server_stats(stats: Stats): CifWriter.Category {
return {
data: stats,
name: 'model_server_stats',
......
......@@ -6,7 +6,7 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { CIFEncoder, CIFCategory, CIFField, createCIFEncoder } from 'mol-io/writer/cif'
import { CifWriter } from 'mol-io/writer/cif'
import * as Data from './data-model'
import * as Coords from '../algebra/coordinate'
import VERSION from '../version'
......@@ -15,7 +15,7 @@ import { Column } from 'mol-data/db';
import { ArrayEncoding, ArrayEncoder } from 'mol-io/common/binary-cif';
export default function encode(query: Data.QueryContext, output: Data.QueryOutputStream) {
let w = createCIFEncoder({ binary: query.params.asBinary, encoderName: `VolumeServer ${VERSION}` });
let w = CifWriter.createEncoder({ binary: query.params.asBinary, encoderName: `VolumeServer ${VERSION}` });
write(w, query);
w.encode();
w.writeTo(output);
......@@ -26,21 +26,19 @@ interface ResultContext {
channelIndex: number
}
type FieldDesc<T> = CIFField<number, T>
function string<T>(name: string, str: (data: T) => string, isSpecified?: (data: T) => boolean): CIFField<number, T> {
function string<T>(name: string, str: (data: T) => string, isSpecified?: (data: T) => boolean): CifWriter.Field<number, T> {
if (isSpecified) {
return CIFField.str(name, (i, d) => str(d), { valueKind: (i, d) => isSpecified(d) ? Column.ValueKind.Present : Column.ValueKind.NotPresent });
return CifWriter.Field.str(name, (i, d) => str(d), { valueKind: (i, d) => isSpecified(d) ? Column.ValueKind.Present : Column.ValueKind.NotPresent });
}
return CIFField.str(name, (i, d) => str(d));
return CifWriter.Field.str(name, (i, d) => str(d));
}
function int32<T>(name: string, value: (data: T) => number): CIFField<number, T> {
return CIFField.int(name, (i, d) => value(d));
function int32<T>(name: string, value: (data: T) => number): CifWriter.Field<number, T> {
return CifWriter.Field.int(name, (i, d) => value(d));
}
function float64<T>(name: string, value: (data: T) => number, digitCount: number = 6): FieldDesc<T> {
return CIFField.float(name, (i, d) => value(d), { digitCount: digitCount, typedArray: Float64Array });
function float64<T>(name: string, value: (data: T) => number, digitCount: number = 6): CifWriter.Field<number, T> {
return CifWriter.Field.float(name, (i, d) => value(d), { digitCount: digitCount, typedArray: Float64Array });
}
interface _vd3d_Ctx {
......@@ -52,7 +50,7 @@ interface _vd3d_Ctx {
sampledValuesInfo: DataFormat.ValuesInfo,
}
const _volume_data_3d_info_fields: FieldDesc<_vd3d_Ctx>[] = [
const _volume_data_3d_info_fields = [
string<_vd3d_Ctx>('name', ctx => ctx.header.channels[ctx.channelIndex]),
int32<_vd3d_Ctx>('axis_order[0]', ctx => ctx.header.axisOrder[0]),
......@@ -92,7 +90,7 @@ const _volume_data_3d_info_fields: FieldDesc<_vd3d_Ctx>[] = [
float64<_vd3d_Ctx>('max_sampled', ctx => ctx.sampledValuesInfo.max)
];
function _volume_data_3d_info(result: ResultContext): CIFCategory {
function _volume_data_3d_info(result: ResultContext): CifWriter.Category {
const ctx: _vd3d_Ctx = {
header: result.query.data.header,
channelIndex: result.channelIndex,
......@@ -137,8 +135,7 @@ function _volume_data_3d(ctx: ResultContext) {
encoder = E.by(E.byteArray)
}
const fields: FieldDesc<typeof data>[] = [CIFField.float('values', _volume_data_3d_number, { encoder, typedArray, digitCount: 6 })]
const fields = [CifWriter.Field.float('values', _volume_data_3d_number, { encoder, typedArray, digitCount: 6 })];
return { data, name: 'volume_data_3d', fields, rowCount: data.length };
}
......@@ -156,7 +153,7 @@ function queryBoxDimension(e: 'a' | 'b', d: number) {
return string<Data.QueryContext>(`query_box_${e}[${d}]`, ctx => pickQueryBoxDimension(ctx, e, d), ctx => ctx.params.box.kind !== 'Cell');
}
const _density_server_result_fields: FieldDesc<Data.QueryContext>[] = [
const _density_server_result_fields = [
string<Data.QueryContext>('server_version', ctx => VERSION),
string<Data.QueryContext>('datetime_utc', ctx => new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')),
string<Data.QueryContext>('guid', ctx => ctx.guid),
......@@ -174,7 +171,7 @@ const _density_server_result_fields: FieldDesc<Data.QueryContext>[] = [
queryBoxDimension('b', 2)
]
function _density_server_result(ctx: Data.QueryContext): CIFCategory {
function _density_server_result(ctx: Data.QueryContext): CifWriter.Category {
return {
data: ctx,
name: 'density_server_result',
......@@ -183,7 +180,7 @@ function _density_server_result(ctx: Data.QueryContext): CIFCategory {
};
}
function write(encoder: CIFEncoder, query: Data.QueryContext) {
function write(encoder: CifWriter.Encoder, query: Data.QueryContext) {
encoder.startDataBlock('SERVER');
encoder.writeCategory(_density_server_result, [query]);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment