From 37a0b07d56be0a011f533078f77f77d9c588c563 Mon Sep 17 00:00:00 2001 From: Sebastian Bittrich <bittrich@hs-mittweida.de> Date: Tue, 4 Jun 2019 17:52:02 -0700 Subject: [PATCH] stub for encoding config --- package-lock.json | Bin 575779 -> 576329 bytes src/mol-io/writer/cif.ts | 53 ++++++++++++++ src/mol-io/writer/cif/encoder/binary.ts | 7 +- src/tests/browser/encoding-config.ts | 91 ++++++++++++++++++++++++ webpack.config.js | 1 + 5 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 src/tests/browser/encoding-config.ts diff --git a/package-lock.json b/package-lock.json index 6c89b0f359c83badbc08f0ea4223fd151c4475cc..e79e6e264ae78f3a1bc547133c07fb54afdc54c2 100644 GIT binary patch delta 512 zcmYk2yDvj=6vy+s=l*Vc`@B-LR1x)_JO&-AZ48|%`WMI@jE&SJji^Q>H4x>}6A2Bm zl8TVuU_c_l)CIBWCaFg!Ta{Z9_YP+`-^b_oIN0#sWxc5-a>_+27;OU&%B|qU*Ly)^ zu?jZ?Ix+OdQ?xdL6>q+|XOt+|F<#~Ra5zCamEr_FE5QrV3R@*Ly8HodlmKQm9diJO zy45&M>@3d1x}=HB)d1H-cSb4#ezdF-6B~8HvEGpx{9fx(Yb#L)kMadIVC<6<(bfzP ze<(QszU&-FF*ybuSU#twY?-vw;%w3lUwUl&AXqSXOKmLUfq+?qV<jO-Sx`Ty+6z;< z3Y+hToJALmXE+|W>%ffilOQT<-4cev#EwThytD~DY;OeWsrE)z@WVc*?N}Hmlx2co z7Ie_aA~oUrF7c@ZT*#4`f6uHGgRXQw4C?UeP?ir1Cs#PILK>C4BU!Vt&}E=$hiG69 I(I{R107QbHtN;K2 delta 371 zcmXAjKS%;$7{>YT{q8QjE(H-aFFg|bBasmfMT6E54i2{lAv6UA88n9E5J+2e<qLs- zAle*6s&8;ep{SN{awtflp&`nqXs}59h6f&apWpL74_W`&kw3jpE`)d&XLP~I(p_Nz z(D<YpepE#j>4EG$@j)H8FJ+Cn30Q@G5LW>T+=VEVIBXT6Xyf+P0XM|d$2_d%gm2Qv zacCHxP(P<`^m^b8je9wm-4#Tvt-&a6Dv~AJA)0B}Da&c_OR#Z8NAU4hvalB~#1-D0 z2ttZC+ovEu$Tw^s3KVlHRdC~nxG}m+tQbi^Z;S=T(fKT`u+ltKDHeTl1^-SZ6{ATq z$ItB~S;zDQ7+820rqR|Rs@d2HnB^@WHYOo}U%H&b)-2fA-6GUQ{xWebE^&S@PmVLq h81zJY5?M1QRqAFf<TA_ll-Z8BGGRq#VP(Kk`v=){ehUBq diff --git a/src/mol-io/writer/cif.ts b/src/mol-io/writer/cif.ts index c191d8a4b..762f1988f 100644 --- a/src/mol-io/writer/cif.ts +++ b/src/mol-io/writer/cif.ts @@ -53,5 +53,58 @@ export namespace CifWriter { return ff && ff.binaryEncoding ? ArrayEncoder.fromEncoding(ff.binaryEncoding) : void 0; } } + }; + + export function createEncodingProviderFromJsonConfig(hints: EncodingStrategyHint[]): EncodingProvider { + return { + get(c, f) { + for (let i = 0; i < hints.length; i++) { + const hint = hints[i]; + if (hint.categoryName === c && hint.columnName === f) { + return resolveEncoding(hint); + } + } + } + } } + + function resolveEncoding(hint: EncodingStrategyHint): ArrayEncoder | undefined { + const precision: number | undefined = hint.precision; + if (precision !== void 0) { + const multiplier = Math.pow(10, precision); + const fixedPoint = E.by(E.fixedPoint(multiplier)); + switch (hint.encoding) { + case 'pack': + return fixedPoint.and(E.integerPacking); + case 'rle': + return fixedPoint.and(E.runLength).and(E.integerPacking); + case 'delta': + return fixedPoint.and(E.delta).and(E.integerPacking); + case 'delta-rle': + return fixedPoint.and(E.delta).and(E.runLength).and(E.integerPacking); + }; + } else { + switch (hint.encoding) { + case 'pack': + return E.by(E.integerPacking); + case 'rle': + return E.by(E.runLength).and(E.integerPacking); + case 'delta': + return E.by(E.delta).and(E.integerPacking); + case 'delta-rle': + return E.by(E.delta).and(E.runLength).and(E.integerPacking); + } + } + } +} + +// defines the information needed to encode certain fields: category and column name as well as encoding tag, precision is optional and identifies float columns +// TODO would be nice to infer strategy and precision if needed +export interface EncodingStrategyHint { + categoryName: string, + columnName: string, + // 'pack', 'rle', 'delta', or 'delta-rle' + encoding: string, + // number of decimal places to keep - must be specified to float columns + precision?: number } \ No newline at end of file diff --git a/src/mol-io/writer/cif/encoder/binary.ts b/src/mol-io/writer/cif/encoder/binary.ts index 9212bcea2..99ee50053 100644 --- a/src/mol-io/writer/cif/encoder/binary.ts +++ b/src/mol-io/writer/cif/encoder/binary.ts @@ -111,12 +111,13 @@ function getDefaultEncoder(type: Field.Type): ArrayEncoder { } function tryGetEncoder(categoryName: string, field: Field, format: Field.Format | undefined, provider: EncodingProvider | undefined) { - if (format && format.encoder) { + // TODO made provider the first check - might break servers/model/query + if (provider && provider.get(categoryName, field.name)) { + return provider.get(categoryName, field.name); + } else if (format && format.encoder) { return format.encoder; } else if (field.defaultFormat && field.defaultFormat.encoder) { return field.defaultFormat.encoder; - } else if (provider) { - return provider.get(categoryName, field.name); } else { return void 0; } diff --git a/src/tests/browser/encoding-config.ts b/src/tests/browser/encoding-config.ts new file mode 100644 index 000000000..b02ed4ea8 --- /dev/null +++ b/src/tests/browser/encoding-config.ts @@ -0,0 +1,91 @@ +import './index.html' +import { CIF, CifCategory, CifField, getCifFieldType } from '../../mol-io/reader/cif'; +import { CifWriter } from '../../mol-io/writer/cif'; +import { classifyFloatArray, classifyIntArray } from '../../mol-io/common/binary-cif'; + +async function parseCif(data: string|Uint8Array) { + const comp = CIF.parse(data); + const parsed = await comp.run(); + if (parsed.isError) throw parsed; + return parsed.result; +} + +async function downloadCif(url: string, isBinary: boolean) { + const data = await fetch(url); + return parseCif(isBinary ? new Uint8Array(await data.arrayBuffer()) : await data.text()); +} + +async function downloadFromPdb(pdb: string) { + const parsed = await downloadCif(`https://webchem.ncbr.muni.cz/ModelServer/static/bcif/${pdb}`, true); + return parsed.blocks[0]; +} + +async function init(props = {}) { + const cif = await downloadFromPdb('1brr') + const encoder = CifWriter.createEncoder({ + binary: true, + encoderName: 'mol*', + binaryEncodingPovider: CifWriter.createEncodingProviderFromJsonConfig([ + { + 'categoryName': 'atom_site', + 'columnName': 'Cartn_y', + 'encoding': 'rle', + 'precision': 0 + }, + { + 'categoryName': 'atom_site', + 'columnName': 'Cartn_z', + 'encoding': 'delta', + 'precision': 1 + }, + { + 'categoryName': 'atom_site', + 'columnName': 'label_seq_id', + 'encoding': 'delta-rle' + } + ]) + }); + + encoder.startDataBlock(cif.header); + for (const c of cif.categoryNames) { + const cat = cif.categories[c]; + const fields: CifWriter.Field[] = []; + for (const f of cat.fieldNames) { + fields.push(classify(f, cat.getField(f)!)) + } + + encoder.writeCategory(getCategoryInstanceProvider(cif.categories[c], fields)); + } + const ret = encoder.getData() as Uint8Array; + + const cif2 = (await parseCif(ret)).blocks[0]; + // should be untouched + console.log(cif2.categories['atom_site'].getField('Cartn_x')); + // should have integer precision + console.log(cif2.categories['atom_site'].getField('Cartn_y')); + // should have 1 decimal place + console.log(cif2.categories['atom_site'].getField('Cartn_z')); + console.log(cif2.categories['atom_site'].getField('label_seq_id')); +} + +init() + +function getCategoryInstanceProvider(cat: CifCategory, fields: CifWriter.Field[]): CifWriter.Category { + return { + name: cat.name, + instance: () => CifWriter.categoryInstance(fields, { data: cat, rowCount: cat.rowCount }) + }; +} + +function classify(name: string, field: CifField): CifWriter.Field { + const type = getCifFieldType(field); + if (type['@type'] === 'str') { + return { name, type: CifWriter.Field.Type.Str, value: field.str, valueKind: field.valueKind }; + } else if (type['@type'] === 'float') { + const encoder = classifyFloatArray(field.toFloatArray({ array: Float64Array })); + return CifWriter.Field.float(name, field.float, { valueKind: field.valueKind, encoder, typedArray: Float64Array }); + } else { + const encoder = classifyIntArray(field.toIntArray({ array: Int32Array })); + return CifWriter.Field.int(name, field.int, { valueKind: field.valueKind, encoder, typedArray: Int32Array }); + } +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 3de9e1565..c171386df 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -98,4 +98,5 @@ module.exports = [ createBrowserTest('render-spheres'), createBrowserTest('render-structure'), createBrowserTest('render-text'), + createBrowserTest('encoding-config') ] \ No newline at end of file -- GitLab