Browse Source

CIF tensor fields should now be working

David Sehnal 7 years ago
parent
commit
6b57151de6

+ 1 - 3
src/mol-data/db/column.ts

@@ -25,8 +25,6 @@ namespace Column {
     export type Schema<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T> | Schema.Tensor
 
     export namespace Schema {
-        export type Scalar<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T>
-
         export type Str = { '@type': 'str', T: string, valueKind: 'str' }
         export type Int = { '@type': 'int', T: number, valueKind: 'int' }
         export type Float = { '@type': 'float', T: number, valueKind: 'float' }
@@ -44,7 +42,7 @@ namespace Column {
         export function vector(dim: number): Tensor { return tensor(Tensors.Vector(dim)); }
         export function matrix(rows: number, cols: number): Tensor { return tensor(Tensors.ColumnMajorMatrix(rows, cols)); }
 
-        export function aliased<T>(t: Schema): Aliased<T> { return t as any as Aliased<T>; }
+        export function aliased<T>(t: Str | Int): Aliased<T> { return t as any as Aliased<T>; }
     }
 
     export interface ToArrayParams<T> {

+ 2 - 6
src/mol-io/reader/cif/binary/field.ts

@@ -9,10 +9,6 @@ import * as Data from '../data-model'
 import { EncodedColumn, decode } from '../../../common/binary-cif'
 import { parseInt as fastParseInt, parseFloat as fastParseFloat } from '../../common/text/number-parser'
 
-function wrap(o: Data.Field) {
-    return { ...o };
-}
-
 export default function Field(column: EncodedColumn): Data.Field {
     const mask = column.mask ? decode(column.mask) as number[] : void 0;
     const data = decode(column.data);
@@ -40,7 +36,7 @@ export default function Field(column: EncodedColumn): Data.Field {
 
     const rowCount = data.length;
 
-    return wrap({
+    return {
         '@array': data,
         isDefined: true,
         rowCount,
@@ -56,5 +52,5 @@ export default function Field(column: EncodedColumn): Data.Field {
         toFloatArray: isNumeric
             ? params => ColumnHelpers.typedArrayWindow(data, params)
             : params => ColumnHelpers.createAndFillArray(rowCount, float, params)
-    });
+    };
 }

+ 30 - 12
src/mol-io/reader/cif/schema.ts

@@ -4,8 +4,9 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import * as Data from './data-model'
 import { Database, Table, Column, ColumnHelpers } from 'mol-data/db'
+import { Tensor } from 'mol-math/linear-algebra'
+import * as Data from './data-model'
 
 export function toDatabase<Schema extends Database.Schema, Frame extends Database<Schema> = Database<Schema>>(schema: Schema, frame: Data.Frame): Frame {
     return createDatabase(schema, frame) as Frame;
@@ -22,18 +23,13 @@ function getColumnCtor(t: Column.Schema): ColumnCtor {
         case 'str': return (f, c, k) => createColumn(t, f, f.str, f.toStringArray);
         case 'int': return (f, c, k) => createColumn(t, f, f.int, f.toIntArray);
         case 'float': return (f, c, k) => createColumn(t, f, f.float, f.toFloatArray);
-        case 'tensor': return (f, c, k) => {
-            const space = t.space;
-            const value = (row: number) => Data.getTensor(c, k, space, row);
-            return createColumn(t, f, value, params => ColumnHelpers.createAndFillArray(f.rowCount, value, params));
-        }
+        case 'tensor': throw new Error(`Use createTensorColumn instead.`);
     }
 }
 
-
 function createColumn<T>(schema: Column.Schema, field: Data.Field, value: (row: number) => T, toArray: Column<T>['toArray']): Column<T> {
     return {
-        schema: schema,
+        schema,
         '@array': field['@array'],
         isDefined: field.isDefined,
         rowCount: field.rowCount,
@@ -44,6 +40,24 @@ function createColumn<T>(schema: Column.Schema, field: Data.Field, value: (row:
     };
 }
 
+function createTensorColumn(schema: Column.Schema.Tensor, category: Data.Category, key: string): Column<Tensor> {
+    const space = schema.space;
+    const first = category.getField(`${key}[1]`) || Column.Undefined(category.rowCount, schema);
+    const value = (row: number) => Data.getTensor(category, key, space, row);
+    const toArray: Column<Tensor>['toArray'] = params => ColumnHelpers.createAndFillArray(category.rowCount, value, params)
+
+    return {
+        schema,
+        '@array': void 0,
+        isDefined: first.isDefined,
+        rowCount: category.rowCount,
+        value,
+        valueKind: first.valueKind,
+        areValuesEqual: (rowA, rowB) => Tensor.areEqualExact(value(rowA), value(rowB)),
+        toArray
+    };
+}
+
 class CategoryTable implements Table<any> { // tslint:disable-line:class-name
     _rowCount: number;
     _columns: ReadonlyArray<string>;
@@ -57,13 +71,17 @@ class CategoryTable implements Table<any> { // tslint:disable-line:class-name
         this._schema = schema;
         const cache = Object.create(null);
         for (const k of fieldKeys) {
-            const cType = schema[k];
-            const ctor = getColumnCtor(cType);
             Object.defineProperty(this, k, {
                 get: function() {
                     if (cache[k]) return cache[k];
-                    const field = category.getField(k);
-                    cache[k] = !!field ? ctor(field, category, k) : Column.Undefined(category.rowCount, cType);
+                    const cType = schema[k];
+                    if (cType.valueKind === 'tensor') {
+                        cache[k] = createTensorColumn(cType, category, k);
+                    } else {
+                        const ctor = getColumnCtor(cType);
+                        const field = category.getField(k);
+                        cache[k] = !!field ? ctor(field, category, k) : Column.Undefined(category.rowCount, cType);
+                    }
                     return cache[k];
                 },
                 enumerable: true,

+ 7 - 0
src/mol-math/linear-algebra/tensor.ts

@@ -75,6 +75,13 @@ export namespace Tensor {
         return vec;
     }
 
+    export function areEqualExact(a: Tensor, b: Tensor) {
+        const len = a.length;
+        if (len !== b.length) return false;
+        for (let i = 0; i < len; i++) if (a[i] !== b[i]) return false;
+        return true;
+    }
+
     function accessors(layout: Layout): { get: Space['get'], set: Space['set'] } {
         const { dimensions, axisOrderFastToSlow: ao } = layout;
         switch (dimensions.length) {

+ 5 - 4
src/perf-tests/structure.ts

@@ -243,8 +243,11 @@ export namespace PropertyAccess {
 
     export async function run() {
         //const { structures, models } = await readCIF('./examples/1cbs_full.bcif');
-        const { structures, models } = await readCIF('e:/test/quick/3j3q_full.bcif');
-        //const { structures, models } = await readCIF('e:/test/quick/1cbs_updated.cif');
+        const { structures, models, mmcif } = await readCIF('e:/test/quick/3j3q_full.bcif');
+        //const { structures, models, mmcif } = await readCIF('e:/test/quick/1cbs_updated.cif');
+
+        console.log(mmcif.pdbx_struct_oper_list.matrix.toArray());
+        console.log(mmcif.pdbx_struct_oper_list.vector.toArray());
 
         //const { structures, models } = await readCIF('e:/test/molstar/3j3q.bcif');
 
@@ -255,8 +258,6 @@ export namespace PropertyAccess {
 
         // return;
 
-        console.log('parsed');
-
         console.log(baseline(models[0]));
         console.log(sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.atom)));
         console.log(sumPropertySegmented(structures[0], l => l.unit.model.conformation.atomId.value(l.atom)));