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

working on data model

parent 77114efe
No related branches found
No related tags found
No related merge requests found
......@@ -284,9 +284,9 @@ describe('ordered set', () => {
const t = Object.create(null);
for (let s = it.move(); !it.done; s = it.move()) {
for (let j = s.start; j < s.end; j++) {
const x = t[s.segmentIndex];
const x = t[s.segment];
const v = OrderedSet.getAt(data, j);
if (!x) t[s.segmentIndex] = [v];
if (!x) t[s.segment] = [v];
else x[x.length] = v;
}
}
......
......@@ -7,13 +7,13 @@
import Iterator from '../iterator'
import OrderedSet from '../ordered-set'
class SegmentIterator implements Iterator<{ segmentIndex: number } & OrderedSet.IndexRange> {
class SegmentIterator implements Iterator<{ segment: number } & OrderedSet.IndexRange> {
private segmentRange = OrderedSet.IndexRange();
private setRange = OrderedSet.IndexRange();
private value = { segmentIndex: 0, start: 0, end: 0 };
private value = { segment: 0, start: 0, end: 0 };
private last: number = 0;
[Symbol.iterator]() { return new SegmentIterator(this.segments, this.set); };
[Symbol.iterator]() { return new SegmentIterator(this.segments, this.set, this.start, this.end); };
done: boolean = false;
next() {
......@@ -27,7 +27,7 @@ class SegmentIterator implements Iterator<{ segmentIndex: number } & OrderedSet.
if (!this.updateValue()) {
this.updateSegmentRange();
} else {
this.value.segmentIndex = this.segmentRange.start++;
this.value.segment = this.segmentRange.start++;
break;
}
}
......@@ -41,11 +41,11 @@ class SegmentIterator implements Iterator<{ segmentIndex: number } & OrderedSet.
private updateValue() {
const segmentEnd = OrderedSet.getAt(this.segments, this.segmentRange.start + 1);
const end = OrderedSet.getPredIndexInRange(this.set, segmentEnd, this.setRange);
const setEnd = OrderedSet.getPredIndexInRange(this.set, segmentEnd, this.setRange);
this.value.start = this.setRange.start;
this.value.end = end;
this.setRange.start = end;
return end > this.value.start;
this.value.end = setEnd;
this.setRange.start = setEnd;
return setEnd > this.value.start;
}
private updateSegmentRange() {
......@@ -55,15 +55,18 @@ class SegmentIterator implements Iterator<{ segmentIndex: number } & OrderedSet.
this.done = this.segmentRange.end <= this.segmentRange.start;
}
constructor(private segments: OrderedSet, private set: OrderedSet) {
constructor(private segments: OrderedSet, private set: OrderedSet, private start: number, private end: number) {
this.last = OrderedSet.max(segments);
this.setRange.end = OrderedSet.size(set);
this.setRange.start = start;
this.setRange.end = end;
this.updateSegmentRange();
}
}
function createIterator(segments: OrderedSet, set: OrderedSet) {
return new SegmentIterator(segments, set);
function createIterator(segments: OrderedSet, set: OrderedSet, range?: OrderedSet.IndexRange) {
const start = !!range ? range.start : 0;
const end = !!range ? range.end : OrderedSet.size(set);
return new SegmentIterator(segments, set, start, end);
}
export default createIterator
\ No newline at end of file
// TODO
\ No newline at end of file
......@@ -14,7 +14,7 @@ describe('atom set', () => {
function setToPairs(set: AtomSet): ArrayLike<IntTuple.Unpacked> {
const ret = [];
const it = AtomSet.values(set);
const it = AtomSet.atoms(set);
for (let v = it.move(); !it.done; v = it.move()) ret[ret.length] = IntTuple.create(v.fst, v.snd);
return ret;
}
......@@ -22,10 +22,10 @@ describe('atom set', () => {
it('singleton pair', () => {
const set = AtomSet.create(p(10, 11));
expect(setToPairs(set)).toEqual([p(10, 11)]);
expect(AtomSet.has(set, r(10, 11))).toBe(true);
expect(AtomSet.has(set, r(11, 11))).toBe(false);
expect(AtomSet.getAt(set, 0)).toBe(r(10, 11));
expect(AtomSet.size(set)).toBe(1);
expect(AtomSet.hasAtom(set, r(10, 11))).toBe(true);
expect(AtomSet.hasAtom(set, r(11, 11))).toBe(false);
expect(AtomSet.getAtomAt(set, 0)).toBe(r(10, 11));
expect(AtomSet.atomCount(set)).toBe(1);
});
it('singleton number', () => {
......@@ -39,13 +39,13 @@ describe('atom set', () => {
3: OrderedSet.ofRange(0, 1),
});
const ret = [p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)];
expect(AtomSet.size(set)).toBe(ret.length);
expect(AtomSet.atomCount(set)).toBe(ret.length);
expect(setToPairs(set)).toEqual([p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)]);
expect(AtomSet.has(set, r(10, 11))).toBe(false);
expect(AtomSet.has(set, r(3, 0))).toBe(true);
expect(AtomSet.has(set, r(1, 7))).toBe(true);
for (let i = 0; i < AtomSet.size(set); i++) {
expect(AtomSet.getAt(set, i)).toBe(IntTuple.pack1(ret[i]));
expect(AtomSet.hasAtom(set, r(10, 11))).toBe(false);
expect(AtomSet.hasAtom(set, r(3, 0))).toBe(true);
expect(AtomSet.hasAtom(set, r(1, 7))).toBe(true);
for (let i = 0; i < AtomSet.atomCount(set); i++) {
expect(AtomSet.getAtomAt(set, i)).toBe(IntTuple.pack1(ret[i]));
}
});
......@@ -62,11 +62,11 @@ describe('atom set', () => {
}
const ms = AtomSet.create(sets);
for (let i = 0; i < control.length; i++) {
expect(IntTuple.areEqual(AtomSet.getAt(ms, i), control[i])).toBe(true);
expect(IntTuple.areEqual(AtomSet.getAtomAt(ms, i), control[i])).toBe(true);
}
for (let i = 0; i < control.length; i++) {
expect(AtomSet.indexOf(ms, control[i])).toBe(i);
expect(AtomSet.indexOfAtom(ms, control[i])).toBe(i);
}
});
......
......@@ -10,26 +10,28 @@ import IntTuple from '../mol-base/collections/int-tuple'
import * as Base from './atom-set/base'
import createBuilder from './atom-set/builder'
/** A map-like representation of integer set */
/** A map-like representation of grouped atom set */
namespace AtomSet {
export const Empty: AtomSet = Base.Empty as any;
export const create: (data: IntTuple | ArrayLike<IntTuple> | IntTuple | { [id: number]: OrderedSet }) => AtomSet = Base.create as any;
export const keys: (set: AtomSet) => OrderedSet = Base.getKeys as any;
export const keyCount: (set: AtomSet) => number = Base.keyCount as any;
export const hasKey: (set: AtomSet, key: number) => boolean = Base.hasKey as any;
export const geyKey: (set: AtomSet, i: number) => number = Base.getKey as any;
export const units: (set: AtomSet) => OrderedSet = Base.getKeys as any;
export const unitCount: (set: AtomSet) => number = Base.keyCount as any;
export const hasUnit: (set: AtomSet, id: number) => boolean = Base.hasKey as any;
export const getUnitId: (set: AtomSet, i: number) => number = Base.getKey as any;
export const getByKey: (set: AtomSet, key: number) => OrderedSet = Base.getByKey as any;
export const getByIndex: (set: AtomSet, i: number) => OrderedSet = Base.getByIndex as any;
export const has: (set: AtomSet, x: IntTuple) => boolean = Base.hasTuple as any;
export const indexOf: (set: AtomSet, x: IntTuple) => number = Base.indexOf as any;
export const getAt: (set: AtomSet, i: number) => IntTuple = Base.getAt as any;
export const values: (set: AtomSet) => Iterator<IntTuple.Unpacked> = Base.values as any;
export const size: (set: AtomSet) => number = Base.size as any;
export const hashCode: (set: AtomSet) => number = Base.hashCode as any;
export const hasAtom: (set: AtomSet, x: IntTuple) => boolean = Base.hasTuple as any;
export const indexOfAtom: (set: AtomSet, x: IntTuple) => number = Base.indexOf as any;
export const getAtomAt: (set: AtomSet, i: number) => IntTuple = Base.getAt as any;
export const atoms: (set: AtomSet) => Iterator<IntTuple.Unpacked> = Base.values as any;
export const atomCount: (set: AtomSet) => number = Base.size as any;
export const hashCode: (set: AtomSet) => number = Base.hashCode as any;
export const areEqual: (a: AtomSet, b: AtomSet) => boolean = Base.areEqual as any;
export const areIntersecting: (a: AtomSet, b: AtomSet) => boolean = Base.areIntersecting as any;
......@@ -40,6 +42,11 @@ namespace AtomSet {
export function SortedBuilder(parent: AtomSet) { return createBuilder(parent, true); }
export function Builder(parent: AtomSet) { return createBuilder(parent, false); }
// TODO: bounding sphere
// TODO: distance, areWithIn?
// TODO: check connected
// TODO: add "parent" property? how to avoid using too much memory? Transitive parents?
}
interface AtomSet { '@type': 'atom-set' }
......
......@@ -4,16 +4,13 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import OrderedSet from '../mol-base/collections/ordered-set'
interface Conformation {
x: ArrayLike<number>,
y: ArrayLike<number>,
z: ArrayLike<number>,
// Assign a secondary structure type to each residue.
secondaryStructureType: ArrayLike<any>,
secondaryStructureAtomOffsets: OrderedSet
secondaryStructureType: ArrayLike<any>
}
export default Conformation
......@@ -4,8 +4,6 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
// TODO: define property accessor intefaces, graphs, spatial lookups and what have you.
import * as Formats from './model/formats'
import CommonInterface from './model/interfaces/common'
import MacromoleculeInterface from './model/interfaces/common'
......@@ -17,9 +15,9 @@ interface Model {
common: CommonInterface,
macromolecule: MacromoleculeInterface
// Atom offsets of the "i-th chain" stored as a closed-open range [chainOffsets[i], chainOffsets[i + 1])
// Atom offsets of the "i-th chain" stored as a closed-open range [chainSegments[i], chainSegments[i + 1])
chainSegments: OrderedSet,
// Atom offsets of the "i-th residue" stored as a closed-open range [residueOffsets[i], residueOffsets[i + 1])
// Atom offsets of the "i-th residue" stored as a closed-open range [residueSegments[i], residueSegments[i + 1])
residueSegments: OrderedSet,
// Mapping from a residue index to chain index
residueChainIndex: ArrayLike<number>,
......@@ -27,4 +25,4 @@ interface Model {
atomResidueIndex: ArrayLike<number>
}
export default Model
export default Model
\ No newline at end of file
/**
* Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import Structure from './structure'
import Selection from './selection'
interface Query { (s: Structure): Selection }
export default Query
\ No newline at end of file
......@@ -6,4 +6,18 @@
import Structure from './structure'
export type Selection = Structure | Structure[]
\ No newline at end of file
type Selection =
| Structure // each atom is interpreted as a singleton structure
| Structure[]
namespace Selection {
export const structureCount: (sel: Selection) => number = 0 as any;
export const union: (sel: Selection) => Structure = 0 as any;
export const getAt: (sel: Selection, i: number) => Structure = 0 as any;
// TODO: 'structure iterator'
// TODO: selection builders (linear / unique)
// TODO: spatial lookup
}
export default Selection
\ No newline at end of file
......@@ -11,9 +11,11 @@ import Conformation from './conformation'
export interface Operator extends Readonly<{
name: string,
hkl: number[], // defaults to [0, 0, 0] where not appropriate
hkl: number[], // defaults to [0, 0, 0] for non symmetry entries
transform: Mat4,
// cache the inverse of the transform
inverse: Mat4,
// optimize the identity case
isIdentity: boolean
}> { }
......@@ -21,15 +23,10 @@ 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 certain basic data 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,
// Separate the conformation from the data for faster/more straightforward dynamics
conformation: Conformation,
// Determines the operation applied to this unit.
......@@ -43,12 +40,16 @@ export interface Unit extends Readonly<{
getPosition(atom: number, slot: Vec3): Vec3
}
export interface Structure { units: { [id: number]: Unit }, atoms: AtomSet }
export interface Structure extends Readonly<{
units: Readonly<{ [id: number]: Unit }>,
atoms: AtomSet
}> { }
export namespace Structure {
export const Empty: Structure = { units: {}, atoms: AtomSet.Empty };
// TODO: "lift" atom set operators
// TODO: "diff"
}
export default Structure
// export interface Selection { structure: Structure, sets: AtomSet[] }
// type SelectionImpl = Structure | Structure[]
\ No newline at end of file
export default Structure
\ No newline at end of file
// /**
// * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
// *
// * @author David Sehnal <david.sehnal@gmail.com>
// */
// import * as Data from './data'
// import { Selectors } from './selectors'
// import { Vec3, Mat4 } from '../../mol-base/math/linear-algebra'
// let _uid = 0;
// /** Model-related unique identifiers */
// export function getUid() { return _uid++; }
// /** Unit = essentially a list of residues (usually a chain) */
// export interface Unit extends Readonly<{
// operator: Unit.Operator,
// /** The static part (essentially residue annotations) */
// structure: Unit.Structure,
// /** 3D arrangement that often changes with time. */
// conformation: Unit.Conformation,
// /** Position of i-th atom. Special function for this because it's the only one that depends on "operator" */
// atomPosition(i: number, p: Vec3): Vec3,
// /** Property access */
// selectors: Selectors
// }> { }
// export namespace Unit {
// export interface Structure extends Readonly<{
// /** A globally unique identifier for this instance (to easily determine unique structures within a model) */
// id: number,
// /** Source data for this structure */
// data: Data.Structure,
// /** Reference to the data.entities table */
// entity: number,
// /** Reference to the data.chains table */
// chain: number,
// /** Indices into the data.residues table. */
// residues: ArrayLike<number>,
// /** Offsets of atoms in the residue layer. start = offsets[i], endExclusive = offsets[i + 1] */
// atomOffsets: ArrayLike<number>,
// /** Indices into data.atoms table */
// atoms: ArrayLike<number>
// /** Index of a residue in the corresponding residues array. */
// atomResidue: ArrayLike<number>
// }> { }
// export interface Conformation extends Readonly<{
// /** A globally unique identifier for this instance (to easily determine unique structures within a model) */
// id: number,
// positions: Data.Positions,
// /** Per residue secondary structure assignment. */
// secondaryStructure: Data.SecondaryStructures
// }> {
// '@spatialLookup': any, // TODO
// '@boundingSphere': Readonly<{ center: Vec3, radius: number }>,
// '@bonds': Data.Bonds
// }
// export namespace Conformation {
// export function spatialLookup(conformation: Conformation): any {
// throw 'not implemented'
// }
// export function boundingSphere(conformation: Conformation): any {
// throw 'not implemented'
// }
// export function bonds(conformation: Conformation): any {
// throw 'not implemented'
// }
// }
// export type OperatorKind =
// | { kind: 'identity' }
// | { kind: 'symmetry', id: string, hkl: Vec3 }
// | { kind: 'assembly', index: number }
// | { kind: 'custom' }
// export interface Operator extends Readonly<{
// kind: OperatorKind,
// transform: Mat4,
// inverse: Mat4
// }> { }
// export interface SpatialLookup {
// // TODO
// }
// }
// export interface Model extends Readonly<{
// units: Unit[],
// structure: { [id: number]: Unit.Structure },
// conformation: { [id: number]: Unit.Conformation }
// }> {
// '@unitLookup'?: Unit.SpatialLookup,
// /** bonds between units */
// '@unitBonds'?: Data.Bonds
// }
// export namespace Model {
// export function unitLookup(model: Model): Unit.SpatialLookup {
// throw 'not implemented';
// }
// export function unitBonds(model: Model): Data.Bonds {
// throw 'not implemented';
// }
// export function join(a: Model, b: Model): Model {
// return {
// units: [...a.units, ...b.units],
// structure: { ...a.structure, ...b.structure },
// conformation: { ...a.conformation, ...b.conformation }
// }
// }
// }
// export namespace Atom {
// /**
// * Represents a "packed reference" to an atom.
// * This is because selections can then be represented
// * a both number[] and Float64Array(), making it much
// * more efficient than storing an array of objects.
// */
// export type PackedReference = number
// export interface Reference { unit: number, atom: number }
// export type Selection = ArrayLike<PackedReference>
// const { _uint32, _float64 } = (function() {
// const data = new ArrayBuffer(8);
// return { _uint32: new Uint32Array(data), _float64: new Float64Array(data) };
// }());
// export function emptyRef(): Reference { return { unit: 0, atom: 0 }; }
// export function packRef(location: Reference) {
// _uint32[0] = location.unit;
// _uint32[1] = location.atom;
// return _float64[0];
// }
// export function unpackRef(ref: PackedReference) {
// return updateRef(ref, emptyRef());
// }
// export function updateRef(ref: PackedReference, location: Reference): Reference {
// _float64[0] = ref;
// location.unit = _uint32[0];
// location.atom = _uint32[1];
// return location;
// }
// }
// export interface Selector<T> {
// '@type': T,
// create(m: Model, u: number): Selector.Field<T>
// }
// export function Selector<T>(create: (m: Model, u: number) => (a: number, v?: T) => T): Selector<T> {
// return { create } as Selector<T>;
// }
// export namespace Selector {
// export type Field<T> = (a: number, v?: T) => T;
// export type Category = { [s: string]: Selector<any> };
// export type Unit<C extends Category> = { [F in keyof C]: Field<C[F]['@type']> }
// export type Set<S extends { [n: string]: Category }> = { [C in keyof S]: Unit<S[C]> }
// }
\ No newline at end of file
......@@ -26,20 +26,20 @@ export namespace Iteration {
export function iterators() {
let s = 0;
const it = AtomSet.values(ms);
const it = AtomSet.atoms(ms);
for (let v = it.move(); !it.done; v = it.move()) s += v.snd;
return s;
}
export function elementAt() {
let s = 0;
for (let i = 0, _i = AtomSet.size(ms); i < _i; i++) s += IntTuple.snd(AtomSet.getAt(ms, i));
for (let i = 0, _i = AtomSet.atomCount(ms); i < _i; i++) s += IntTuple.snd(AtomSet.getAtomAt(ms, i));
return s;
}
export function manual() {
let s = 0;
const keys = AtomSet.keys(ms);
const keys = AtomSet.units(ms);
for (let i = 0, _i = OrdSet.size(keys); i < _i; i++) {
const set = AtomSet.getByKey(ms, OrdSet.getAt(keys, i));
for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
......@@ -51,7 +51,7 @@ export namespace Iteration {
export function manual1() {
let s = 0;
for (let i = 0, _i = AtomSet.keyCount(ms); i < _i; i++) {
for (let i = 0, _i = AtomSet.unitCount(ms); i < _i; i++) {
const set = AtomSet.getByIndex(ms, i);
for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
s += OrdSet.getAt(set, j);
......@@ -237,7 +237,7 @@ export function testSegments() {
for (let s = it.move(); !it.done; s = it.move()) {
for (let j = s.start; j < s.end; j++) {
console.log(`${s.segmentIndex}: ${OrdSet.getAt(data, j)}`);
console.log(`${s.segment}: ${OrdSet.getAt(data, j)}`);
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment