Explorar el Código

stub for encoding config

Sebastian Bittrich hace 5 años
padre
commit
37a0b07d56

+ 31 - 12
package-lock.json

@@ -4950,7 +4950,8 @@
           "version": "2.1.1",
           "resolved": false,
           "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -4974,13 +4975,15 @@
           "version": "1.0.0",
           "resolved": false,
           "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "resolved": false,
           "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
           "dev": true,
+          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -4997,19 +5000,22 @@
           "version": "1.1.0",
           "resolved": false,
           "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "resolved": false,
           "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "resolved": false,
           "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -5140,7 +5146,8 @@
           "version": "2.0.3",
           "resolved": false,
           "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "ini": {
           "version": "1.3.5",
@@ -5154,6 +5161,7 @@
           "resolved": false,
           "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
           "dev": true,
+          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -5170,6 +5178,7 @@
           "resolved": false,
           "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
           "dev": true,
+          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -5178,13 +5187,15 @@
           "version": "0.0.8",
           "resolved": false,
           "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "minipass": {
           "version": "2.3.5",
           "resolved": false,
           "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
           "dev": true,
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -5205,6 +5216,7 @@
           "resolved": false,
           "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
           "dev": true,
+          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -5293,7 +5305,8 @@
           "version": "1.0.1",
           "resolved": false,
           "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -5307,6 +5320,7 @@
           "resolved": false,
           "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
           "dev": true,
+          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -5402,7 +5416,8 @@
           "version": "5.1.2",
           "resolved": false,
           "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -5444,6 +5459,7 @@
           "resolved": false,
           "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
           "dev": true,
+          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -5465,6 +5481,7 @@
           "resolved": false,
           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
           "dev": true,
+          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -5513,13 +5530,15 @@
           "version": "1.0.2",
           "resolved": false,
           "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "yallist": {
           "version": "3.0.3",
           "resolved": false,
           "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
-          "dev": true
+          "dev": true,
+          "optional": true
         }
       }
     },
@@ -11941,7 +11960,7 @@
         },
         "minimist": {
           "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
           "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
           "dev": true
         }

+ 53 - 0
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
 }

+ 4 - 3
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;
     }

+ 91 - 0
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 });
+    }
+}

+ 1 - 0
webpack.config.js

@@ -98,4 +98,5 @@ module.exports = [
     createBrowserTest('render-spheres'),
     createBrowserTest('render-structure'),
     createBrowserTest('render-text'),
+    createBrowserTest('encoding-config')
 ]