Browse Source

data model

David Sehnal 7 years ago
parent
commit
ebc03085c0

+ 12 - 0
src/mol-base/_spec/collections.spec.ts

@@ -9,6 +9,7 @@ import IntTuple from '../collections/int-tuple'
 import * as Sort from '../collections/sort'
 import OrderedSet from '../collections/ordered-set'
 import LinkedIndex from '../collections/linked-index'
+import EquivalenceClasses from '../collections/equivalence-classes'
 
 function iteratorToArray<T>(it: Iterator<T>): T[] {
     const ret = [];
@@ -312,4 +313,15 @@ describe('linked-index', () => {
         expect(index.has(0)).toBe(false);
         expect(index.has(1)).toBe(false);
     });
+});
+
+describe('equiv-classes', () => {
+    it('integer mod classes', () => {
+        const cls = EquivalenceClasses<number, number>(x => x % 2, (a, b) => (a - b) % 2 === 0);
+        for (let i = 0; i < 6; i++) cls.add(i, i);
+
+        expect(cls.groups.length).toBe(2);
+        expect(cls.groups[0]).toEqual([0, 2, 4]);
+        expect(cls.groups[1]).toEqual([1, 3, 5]);
+    });
 });

+ 47 - 0
src/mol-base/collections/equivalence-classes.ts

@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+class EquivalenceClassesImpl<K, V> {
+    private id = 0;
+    private byHash: { [hash: number]: { id: number, keys: K[], value: V }[] } = Object.create(null);
+
+    readonly groups: K[][] = [];
+
+    private createGroup(key: K, value: V) {
+        const id = this.id++;
+        const keys = [key];
+        this.groups[id] = keys;
+        return { id, keys, value };
+    }
+
+    add(key: K, a: V) {
+        const hash = this.getHash(a);
+        if (this.byHash[hash]) {
+            const groups = this.byHash[hash];
+            for (const group of groups) {
+                if (this.areEqual(a, group.value)) {
+                    group.keys[group.keys.length] = key;
+                    return group.id;
+                }
+            }
+            const group = this.createGroup(key, a);
+            groups[groups.length] = group;
+            return group.id;
+        } else {
+            const group = this.createGroup(key, a);
+            this.byHash[hash] = [group];
+            return group.id;
+        }
+    }
+
+    constructor(private getHash: (v: V) => any, private areEqual: (a: V, b: V) => boolean) { }
+}
+
+function EquivalenceClasses<K, V>(getHash: (x: V) => any, areEqual: (a: V, b: V) => boolean) {
+    return new EquivalenceClassesImpl<K, V>(getHash, areEqual);
+}
+
+export default EquivalenceClasses;

+ 2 - 2
src/mol-base/math/linear-algebra.ts

@@ -5,9 +5,9 @@
  */
 
 /*
- * This code has been modified from https://github.com/toji/gl-matrix/, 
+ * This code has been modified from https://github.com/toji/gl-matrix/,
  * copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights

+ 13 - 0
src/mol-data/model.ts

@@ -0,0 +1,13 @@
+/**
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+// TODO: define property accessor intefaces, graphs, spatial lookups and what have you.
+
+interface Model {
+
+}
+
+export default Model

+ 54 - 0
src/mol-data/structure.ts

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Vec3, Mat4 } from '../mol-base/math/linear-algebra'
+import AtomSet from './atom-set'
+import Model from './model'
+
+export type Operator =
+    | { kind: Operator.Kind.Identity }
+    | { kind: Operator.Kind.Symmetry, hkl: number[], index: number, name: string, transform: Mat4, inverse: Mat4 }
+    | { kind: Operator.Kind.Assembly, assemblyName: string, index: number, transform: Mat4, inverse: Mat4 }
+    | { kind: Operator.Kind.Custom, name: string, transform: Mat4, inverse: Mat4 }
+
+export namespace Operator {
+    export enum Kind { Identity, Symmetry, Assembly, Custom }
+}
+
+export interface Unit extends Readonly<{
+    // Structure-level unique identifier of the unit.
+    id: number,
+
+    // Each unit can only contain atoms from a single "chain"
+    // the reason for this is to make symmetry and assembly transforms fast
+    // without having to look at the actual contents of the unit
+    // multiple units can point to the same chain
+    chainIndex: number,
+
+    // Provides access to the underlying data.
+    model: Model,
+
+    // Determines the operation applied to this unit.
+    // The transform and and inverse a baked into the "getPosition" function
+    operator: Operator
+}> {
+    // returns the untransformed position. Used for spatial queries.
+    getInvariantPosition(atom: number, slot: Vec3): Vec3
+
+    // gets the transformed position of the specified atom
+    getPosition(atom: number, slot: Vec3): Vec3
+}
+
+export interface Structure { units: { [id: number]: Unit }, atoms: AtomSet }
+
+export namespace Structure {
+    export const Empty: Structure = { units: {}, atoms: AtomSet.Empty };
+
+    export enum Algebra { AddUnit, RemoveUnit, UpdateConformation /* specify which units map to which */ }
+}
+
+// export interface Selection { structure: Structure, sets: AtomSet[] }
+// type SelectionImpl = Structure | Structure[]

+ 3 - 3
src/mol-io/reader/cif/text/parser.ts

@@ -567,7 +567,7 @@ async function parseInternal(data: string, ctx: Computation.Context) {
         // Data block
         if (token === CifTokenType.Data) {
             if (inSaveFrame) {
-                return error(tokenizer.lineNumber, "Unexpected data block inside a save frame.");
+                return error(tokenizer.lineNumber, 'Unexpected data block inside a save frame.');
             }
             if (Object.keys(blockCategories).length > 0) {
                 dataBlocks.push(Data.Block(blockCategories, blockHeader, saveFrames));
@@ -586,7 +586,7 @@ async function parseInternal(data: string, ctx: Computation.Context) {
                 inSaveFrame = false;
             } else {
                 if (inSaveFrame) {
-                    return error(tokenizer.lineNumber, "Save frames cannot be nested.");
+                    return error(tokenizer.lineNumber, 'Save frames cannot be nested.');
                 }
                 inSaveFrame = true;
                 saveCategories = Object.create(null);
@@ -613,7 +613,7 @@ async function parseInternal(data: string, ctx: Computation.Context) {
 
     // Check if the latest save frame was closed.
     if (inSaveFrame) {
-        return error(tokenizer.lineNumber, "Unfinished save frame (`" + saveFrame.header + "`).");
+        return error(tokenizer.lineNumber, 'Unfinished save frame (`' + saveFrame.header + '`).');
     }
 
     if (Object.keys(blockCategories).length > 0) {