From 4492bd6134544a1b7240d40b511486fd178f381c Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Fri, 6 Oct 2017 14:04:02 +0200 Subject: [PATCH] Working on structure data model --- src/structure/data.ts | 14 ++++ src/structure/model.ts | 130 ++++++++++++++++++++---------- src/structure/selectors.ts | 11 +++ src/structure/selectors/common.ts | 47 +++++++++++ src/structure/selectors/mmcif.ts | 34 ++++++++ src/utils/linear-algebra.ts | 3 +- 6 files changed, 194 insertions(+), 45 deletions(-) create mode 100644 src/structure/selectors.ts create mode 100644 src/structure/selectors/common.ts create mode 100644 src/structure/selectors/mmcif.ts diff --git a/src/structure/data.ts b/src/structure/data.ts index 09332de8d..d162fc1b3 100644 --- a/src/structure/data.ts +++ b/src/structure/data.ts @@ -32,6 +32,20 @@ export interface Chains extends DataTable<Chain> { } export interface Entity { key: number, id: string } export interface Entities extends DataTable<Entity> { } +export interface Bonds extends Readonly<{ + /** + * Where bonds for atom A start and end. + * Start at idx, end at idx + 1 + */ + offset: ArrayLike<number>, + neighbor: ArrayLike<number>, + + order: ArrayLike<number>, + flags: ArrayLike<number>, + + count: number +}> { } + export type SourceData = | { kind: 'mmCIF', data: any } // TODO | { kind: 'custom', data: any } // TODO diff --git a/src/structure/model.ts b/src/structure/model.ts index 47b1e863e..2ec048765 100644 --- a/src/structure/model.ts +++ b/src/structure/model.ts @@ -5,22 +5,32 @@ */ import * as Data from './data' +import { Selectors } from './selectors' import { Vec3, Mat4 } from '../utils/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) */ - structre: Unit.Structure, + structure: Unit.Structure, /** 3D arrangement that often changes with time. */ - conformation: Unit.Conformation + 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, - /** A globally unique number for this instance (to easily determine unique structures within a model) */ - key: number, /** Reference to the data.entities table */ entity: number, /** Reference to the data.chains table */ @@ -29,32 +39,40 @@ export namespace Unit { 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: number + atomResidue: ArrayLike<number> }> { } - export interface Bonds extends Readonly<{ - /** - * Where bonds for atom A start and end. - * Start at idx, end at idx + 1 - */ - offset: ArrayLike<number>, - neighbor: ArrayLike<number>, + export interface Conformation extends Readonly<{ + /** A globally unique identifier for this instance (to easily determine unique structures within a model) */ + id: number, - order: ArrayLike<number>, - flags: ArrayLike<number>, + positions: Data.Positions, - count: number - }> { } + /** Per residue secondary structure assignment. */ + secondaryStructure: Data.SecondaryStructures, - export interface Conformation extends Readonly<{ - positions: Data.Positions - spatialLookup: any, // TODO - boundingSphere: { readonly center: Vec3, readonly radius: number }, - secodaryStructure: Data.SecondaryStructures, - bonds: Bonds + '@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 } @@ -66,31 +84,38 @@ export namespace Unit { inverse: Mat4 }> { } - export interface Lookup3D { + export interface SpatialLookup { // TODO } } export interface Model extends Readonly<{ - index: number, + units: Unit[], + + structure: { [id: number]: Unit.Structure }, + conformation: { [id: number]: Unit.Conformation }, - structure: Model.Structure, - conformation: Model.Conformation + '@unitLookup'?: Unit.SpatialLookup, + /** bonds between units */ + '@unitBonds'?: Data.Bonds }> { } export namespace Model { - // TODO: model residues between units - // use a map of map of bonds? + export function unitLookup(model: Model): Unit.SpatialLookup { + throw 'not implemented'; + } - export interface Structure extends Readonly<{ - operators: Unit.Operator[], - units: Unit.Structure[] - }> { } + export function unitBonds(model: Model): Data.Bonds { + throw 'not implemented'; + } - export interface Conformation extends Readonly<{ - units: Unit.Conformation[], - spatialLookup: Unit.Lookup3D - }> { } + 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 { @@ -100,30 +125,49 @@ export namespace Atom { * a both number[] and Float64Array(), making it much * more efficient than storing an array of objects. */ - export type Reference = number - export interface Location { unit: number, atom: number } + 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 emptyLocation(): Location { return { unit: 0, atom: 0 }; } + export function emptyLocation(): Reference { return { unit: 0, atom: 0 }; } - export function getRef(location: Location) { + export function packRef(location: Reference) { _uint32[0] = location.unit; _uint32[1] = location.atom; return _float64[0]; } - export function getLocation(ref: Reference) { - return updateLocation(ref, emptyLocation()); + export function unpackRef(ref: PackedReference) { + return updateRef(ref, emptyLocation()); } - export function updateLocation(ref: Reference, location: Location): Location { + 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): (a: number, v?: T) => 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 diff --git a/src/structure/selectors.ts b/src/structure/selectors.ts new file mode 100644 index 000000000..c8e599b3a --- /dev/null +++ b/src/structure/selectors.ts @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Selector } from './model' + +const set = {}; + +export type Selectors = Selector.Set<typeof set> \ No newline at end of file diff --git a/src/structure/selectors/common.ts b/src/structure/selectors/common.ts new file mode 100644 index 000000000..76b4c876f --- /dev/null +++ b/src/structure/selectors/common.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> +// */ + +// import { Selector } from '../model' +// //import * as Data from '../data' +// //import { Vec3 } from '../../utils/linear-algebra' + +// export const atom = { +// name: Selector((m, u) => { +// const unit = m.units[u].structure; +// const atoms = unit.atoms; +// const name = unit.data.atoms.name; +// return a => name[atoms[a]]; +// }), +// // position: Selector<Vec3>((m, u) => { +// // const unit = m.units[u].structure; +// // const atoms = unit.atoms; +// // const { positions: { x, y, z } } = m.conformation[u]; +// // const { operator: { transform } } = unit; +// // return (atom, position) => { +// // const a = atoms[atom]; +// // const p = position || Vec3.zero(); +// // Vec3.set(p, x[a], y[a], z[a]); +// // return Vec3.transformMat4(p, p, transform); +// // }; +// // }), +// // inversePosition: Selector<Vec3>((m, u) => { +// // const unit = m.structure[u]; +// // const atoms = unit.atoms; +// // const { positions: { x, y, z } } = m.conformation[u]; +// // const { operator: { inverse } } = unit; + +// // return (atom, position) => { +// // const a = atoms[atom]; +// // const p = position || Vec3.zero(); +// // Vec3.set(p, x[a], y[a], z[a]); +// // return Vec3.transformMat4(p, p, inverse); +// // }; +// // }) +// } + +// export const residue = { + +// } \ No newline at end of file diff --git a/src/structure/selectors/mmcif.ts b/src/structure/selectors/mmcif.ts new file mode 100644 index 000000000..08a95c232 --- /dev/null +++ b/src/structure/selectors/mmcif.ts @@ -0,0 +1,34 @@ +// /** +// * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author David Sehnal <david.sehnal@gmail.com> +// */ + +// import { Model, Unit, PropertyGetterProvider } from '../model' +// import * as Data from '../data' +// //import { Vec3 } from '../../utils/linear-algebra' + +// // function provider<T>(p: (model: Model) => Property<T>): PropertyProvider<T> { +// // return p; +// // } + +// function atomPropertyProvider<T>(property: (ps: Model['structure']['properties']) => ArrayLike<T>): PropertyGetterProvider<T> { +// return m => { +// const a = m.structure.properties.atoms; +// const p = property(m.structure.properties); +// return ({ unit, atom }) => p[a[unit][atom]]; +// }; +// } + +// function unitStructureProvider<T>(p: (structure: Unit.Structure, data: Data.Structure, atom: number) => T): PropertyGetterProvider<T> { +// return m => { +// const units = m.structure.units; +// const data = m.structure.properties.data; +// return ({ unit, atom }) => p(units[unit], data[unit], atom); +// }; +// } + +// export const atom_site = { +// label_atom_id: atomPropertyProvider(ps => ps.), +// label_comp_id: unitStructureProvider((u, d, a) => d.residues.name[u.atomResidue[a]]) +// } \ No newline at end of file diff --git a/src/utils/linear-algebra.ts b/src/utils/linear-algebra.ts index fa6af909b..10f1ea666 100644 --- a/src/utils/linear-algebra.ts +++ b/src/utils/linear-algebra.ts @@ -572,8 +572,7 @@ export namespace Vec3 { export function transformMat4(out: number[], a: number[], m: number[]) { let x = a[0], y = a[1], z = a[2], - w = m[3] * x + m[7] * y + m[11] * z + m[15]; - w = w || 1.0; + w = (m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0; out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; -- GitLab