From ed28bf3d3670ce4a08846c974b077cbddaed0a9e Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Thu, 2 Nov 2017 00:30:17 +0100 Subject: [PATCH] refactoring --- .../collections/integer/impl/ordered-set.ts | 2 +- .../collections/integer/impl/sorted-array.ts | 2 +- .../collections/integer/sorted-array.ts | 3 +- src/mol-base/collections/iterator.ts | 6 +- src/mol-base/utils/bit-flags.ts | 4 ++ src/mol-data/model/properties/conformation.ts | 4 +- src/mol-data/structure.ts | 4 +- src/mol-data/structure/atom-set.ts | 2 +- src/mol-data/structure/atom-set/properties.ts | 4 ++ src/mol-data/structure/atom.ts | 13 ++++ src/mol-data/structure/base.ts | 4 +- src/mol-data/structure/property.ts | 69 ------------------- src/perf-tests/structure.ts | 63 +++++++++-------- 13 files changed, 65 insertions(+), 115 deletions(-) delete mode 100644 src/mol-data/structure/property.ts diff --git a/src/mol-base/collections/integer/impl/ordered-set.ts b/src/mol-base/collections/integer/impl/ordered-set.ts index dab3f4db5..255c7772f 100644 --- a/src/mol-base/collections/integer/impl/ordered-set.ts +++ b/src/mol-base/collections/integer/impl/ordered-set.ts @@ -248,7 +248,7 @@ function subtractIS(a: I, b: S) { let offset = 0; for (let i = min; i < fst; i++) ret[offset++] = i; for (let i = fst; i <= last; i++) { - if (S.indexOfInterval(b, i, interval) < 0) ret[offset++] = i; + if (S.indexOfInInterval(b, i, interval) < 0) ret[offset++] = i; } for (let i = last + 1; i <= max; i++) ret[offset++] = i; return ofSortedArray(ret); diff --git a/src/mol-base/collections/integer/impl/sorted-array.ts b/src/mol-base/collections/integer/impl/sorted-array.ts index 27debf6fc..8056ad029 100644 --- a/src/mol-base/collections/integer/impl/sorted-array.ts +++ b/src/mol-base/collections/integer/impl/sorted-array.ts @@ -35,7 +35,7 @@ export function indexOf(xs: Nums, v: number) { const l = xs.length; return l === 0 ? -1 : xs[0] <= v && v <= xs[l - 1] ? binarySearchRange(xs, v, 0, l) : -1; } -export function indexOfInterval(xs: Nums, v: number, bounds: Interval) { +export function indexOfInInterval(xs: Nums, v: number, bounds: Interval) { const l = xs.length; const s = Interval.start(bounds), e = Interval.end(bounds); return l === 0 || e <= s ? -1 : xs[s] <= v && v <= xs[e - 1] ? binarySearchRange(xs, v, s, e) : -1; diff --git a/src/mol-base/collections/integer/sorted-array.ts b/src/mol-base/collections/integer/sorted-array.ts index 4f38bf9a6..701ea8ea3 100644 --- a/src/mol-base/collections/integer/sorted-array.ts +++ b/src/mol-base/collections/integer/sorted-array.ts @@ -16,8 +16,7 @@ namespace SortedArray { export const has: (array: SortedArray, x: number) => boolean = Impl.has as any; export const indexOf: (array: SortedArray, x: number) => number = Impl.indexOf as any; - export const indexOfInterval: (array: SortedArray, x: number, bounds: Interval) => number = Impl.indexOfInterval as any; - //export const getAt: (array: SortedArray, i: number) => number = Impl.getAt as any; + export const indexOfInInterval: (array: SortedArray, x: number, bounds: Interval) => number = Impl.indexOfInInterval as any; export const start: (array: SortedArray) => number = Impl.start as any; export const end: (array: SortedArray) => number = Impl.end as any; diff --git a/src/mol-base/collections/iterator.ts b/src/mol-base/collections/iterator.ts index 9d4ff64d6..6b5906801 100644 --- a/src/mol-base/collections/iterator.ts +++ b/src/mol-base/collections/iterator.ts @@ -5,12 +5,10 @@ */ /** - * ES6 compatible iterator. - * - * "Idiomatic" usage is to use the move function, because it does not make any allocations. + * "Idiomatic" usage: * * const it = ...; - * while (it.hasNext) { const v = it.move(); ... } + * while (it.hasNext) { const v = it.move(); ... } */ interface Iterator<T> { readonly hasNext: boolean, diff --git a/src/mol-base/utils/bit-flags.ts b/src/mol-base/utils/bit-flags.ts index e5cd20290..acf1fc2f5 100644 --- a/src/mol-base/utils/bit-flags.ts +++ b/src/mol-base/utils/bit-flags.ts @@ -7,7 +7,11 @@ interface BitFlags<Flags> { '@type': Flags } namespace BitFlags { + export function create<F>(flags: F): BitFlags<F> { return flags as any; } + export function has<F>(flags: BitFlags<F>, flag: F) { return ((flags as any) & (flag as any)) !== 0; } + // toCheck must be non-zero + export function hasAll<F>(flags: BitFlags<F>, toCheck: BitFlags<F>) { return !!toCheck && ((flags as any) & (toCheck as any)) === (toCheck as any); } } export default BitFlags \ No newline at end of file diff --git a/src/mol-data/model/properties/conformation.ts b/src/mol-data/model/properties/conformation.ts index f023ba707..7ea3c5243 100644 --- a/src/mol-data/model/properties/conformation.ts +++ b/src/mol-data/model/properties/conformation.ts @@ -11,13 +11,15 @@ interface Conformation { id: UUID, // ID is part of conformation because mmCIF is a leaky abstraction - // thats assigns different atom ids to corresponding atoms in different models + // that assigns different atom ids to corresponding atoms in different models // ... go figure. atomId: Column<number>, occupancy: Column<number>, B_iso_or_equiv: Column<number> + // Coordinates. Generally, not to be accessed directly because the coordinate might be + // transformed by an operator. Use Unit.getPosition instead. __x: ArrayLike<number>, __y: ArrayLike<number>, __z: ArrayLike<number> diff --git a/src/mol-data/structure.ts b/src/mol-data/structure.ts index 577211510..4f7f15083 100644 --- a/src/mol-data/structure.ts +++ b/src/mol-data/structure.ts @@ -12,12 +12,12 @@ import * as Base from './structure/base' //import Operator from './structure/operator' // TODO: do "single model" version of the structure? -export interface Structure extends Readonly<{ +interface Structure extends Readonly<{ units: { readonly [id: number]: Unit }, atoms: AtomSet }> { } -export namespace Structure { +namespace Structure { export const Empty = Base.Empty; export const ofModel = Base.ofModel; diff --git a/src/mol-data/structure/atom-set.ts b/src/mol-data/structure/atom-set.ts index d2788a29a..a0524ecdf 100644 --- a/src/mol-data/structure/atom-set.ts +++ b/src/mol-data/structure/atom-set.ts @@ -46,7 +46,7 @@ namespace AtomSet { // TODO: bounding sphere // TODO: distance, areWithIn? // TODO: check connected - // TODO: add "parent" property? how to avoid using too much memory? Transitive parents? + // TODO: add "parent" property? how to avoid using too much memory? Transitive parents? Parent unlinking? } interface AtomSet { '@type': 'atom-set' } diff --git a/src/mol-data/structure/atom-set/properties.ts b/src/mol-data/structure/atom-set/properties.ts index d13a9ee15..6e5dfe593 100644 --- a/src/mol-data/structure/atom-set/properties.ts +++ b/src/mol-data/structure/atom-set/properties.ts @@ -4,3 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ +// TODO: bounding sphere +// TODO: distance, areWithIn? +// TODO: check connected +// TODO: add "parent" property? how to avoid using too much memory? Transitive parents? Parent unlinking? \ No newline at end of file diff --git a/src/mol-data/structure/atom.ts b/src/mol-data/structure/atom.ts index 7a6ef43aa..5dfb6d5da 100644 --- a/src/mol-data/structure/atom.ts +++ b/src/mol-data/structure/atom.ts @@ -5,6 +5,8 @@ */ import Tuple from '../../mol-base/collections/integer/tuple' +import Unit from './unit' +import Structure from '../structure' /** Atom pointer */ interface Atom { '@type': Tuple['@type'] } @@ -17,6 +19,17 @@ namespace Atom { export const index: (a: Atom) => number = Tuple.snd; export const areEqual: (a: Atom, b: Atom) => boolean = Tuple.areEqual; export const hashCode: (a: Atom) => number = Tuple.hashCode; + + /** All the information required to access atom properties */ + export interface Location { unit: Unit, atom: number } + export function Location(): Location { return { unit: {} as any, atom: 0 }; } + export interface Property<T> { (location: Location): T } + export interface Predicate extends Property<boolean> { } + + export function setLocation(structure: Structure, l: Location, atom: Atom) { + l.unit = structure.units[unit(atom)]; + l.atom = index(atom); + } } export default Atom \ No newline at end of file diff --git a/src/mol-data/structure/base.ts b/src/mol-data/structure/base.ts index 1ef19f3db..9732c6a75 100644 --- a/src/mol-data/structure/base.ts +++ b/src/mol-data/structure/base.ts @@ -11,7 +11,7 @@ import Operator from './operator' import AtomSet from './atom-set' import OrderedSet from '../../mol-base/collections/integer/ordered-set' -class Builder { +export class StructureBuilder { private units = Object.create(null); private atoms = Object.create(null); @@ -25,7 +25,7 @@ export const Empty: Structure = { units: {}, atoms: AtomSet.Empty }; export function ofModel(model: Model): Structure { const chains = model.hierarchy.chainSegments; - const builder = new Builder(); + const builder = new StructureBuilder(); for (let c = 0; c < chains.count; c++) { const unit = Unit.create(model, Operator.Identity); diff --git a/src/mol-data/structure/property.ts b/src/mol-data/structure/property.ts deleted file mode 100644 index 42b85e0b6..000000000 --- a/src/mol-data/structure/property.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * 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 Atom from './atom' -import Unit from './unit' -import Model from '../model' -import Column from '../../mol-base/collections/column' - -/** Atom pointer */ -interface Property<T> { (location: Property.Location): T } - -namespace Property { - export interface Predicate extends Property<boolean> { } - - /** All the information required to access atom properties */ - export interface Location { - //structure: Structure, - unit: Unit, - // hierarchy: Model['hierarchy'], - // conformation: Model['conformation'], - atomIndex: number, - // residueIndex: number, - // chainIndex: number - } - - export function createLocation(): Location { - return { - //structure: structure!, - unit: {} as any, - //hierarchy: (!unit ? void 0 : unit.model.hierarchy)!, - //conformation: (!unit ? void 0 : unit.model.conformation)!, - atomIndex: 0 - //residueIndex: 0, - //chainIndex: 0 - }; - } - - export function update(l: Location, structure: Structure, atom: Atom) { - // const u = structure.units[Atom.unit(atom)]; - // const i = Atom.index(atom); - // l.structure = structure; - // l.unit = u; - // l.atomIndex = i; - // l.residueIndex = u.residueIndex[i]; - // l.chainIndex = u.chainIndex[i]; - throw 'not implemented' - } - - export function naive<T>(p: Property<T>) { return p; } - - export function cachedAtomColumn<T>(col: (model: Model) => Column<T>): Property<T> { - let lastUnit: Unit | undefined = void 0; - let cached: ((row: number) => T) | undefined = void 0; - return function (location) { - if (location.unit === lastUnit && !!cached) return cached(location.atomIndex); - lastUnit = location.unit; - cached = col(lastUnit.model).value; - return cached(location.atomIndex); - }; - } - - // TODO: cached versions of other properties. -} - -export default Property \ No newline at end of file diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts index ec9a406c2..88727ac30 100644 --- a/src/perf-tests/structure.ts +++ b/src/perf-tests/structure.ts @@ -12,7 +12,6 @@ import CIF from '../mol-io/reader/cif' import buildModels from '../mol-data/model/builders/mmcif' import { ofModel } from '../mol-data/structure/base' -import Property from '../mol-data/structure/property' import Model from '../mol-data/Model' import Structure from '../mol-data/structure' import OrdSet from '../mol-base/collections/integer/ordered-set' @@ -80,10 +79,10 @@ export namespace PropertyAccess { return s; } - function sumProperty(structure: Structure, p: Property<number>) { + function sumProperty(structure: Structure, p: Atom.Property<number>) { const { atoms, units } = structure; const unitIds = AtomSet.unitIds(atoms); - const l = Property.createLocation(); + const l = Atom.Location(); let s = 0; @@ -92,7 +91,7 @@ export namespace PropertyAccess { const set = AtomSet.unitGetByIndex(atoms, i); for (let j = 0, _j = OrdSet.size(set); j < _j; j++) { - l.atomIndex = OrdSet.getAt(set, j); + l.atom = OrdSet.getAt(set, j); s += p(l); } } @@ -100,10 +99,10 @@ export namespace PropertyAccess { return s; } - function sumPropertySegmented(structure: Structure, p: Property<number>) { + function sumPropertySegmented(structure: Structure, p: Atom.Property<number>) { const { atoms, units } = structure; const unitIds = AtomSet.unitIds(atoms); - const l = Property.createLocation(); + const l = Atom.Location(); let s = 0; @@ -120,7 +119,7 @@ export namespace PropertyAccess { while (residuesIt.hasNext) { const residueSegment = residuesIt.move(); for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { - l.atomIndex = OrdSet.getAt(set, j); + l.atom = OrdSet.getAt(set, j); s += p(l); } } @@ -130,10 +129,10 @@ export namespace PropertyAccess { return s; } - function sumPropertyResidue(structure: Structure, p: Property<number>) { + function sumPropertyResidue(structure: Structure, p: Atom.Property<number>) { const { atoms, units } = structure; const unitIds = AtomSet.unitIds(atoms); - const l = Property.createLocation(); + const l = Atom.Location(); let s = 0; @@ -143,7 +142,7 @@ export namespace PropertyAccess { const set = AtomSet.unitGetByIndex(atoms, i); const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set); while (residuesIt.hasNext) { - l.atomIndex = OrdSet.getAt(set, residuesIt.move().start); + l.atom = OrdSet.getAt(set, residuesIt.move().start); s += p(l); } } @@ -151,16 +150,16 @@ export namespace PropertyAccess { return s; } - function sumPropertyAtomSetIt(structure: Structure, p: Property<number>) { + function sumPropertyAtomSetIt(structure: Structure, p: Atom.Property<number>) { const { atoms, units } = structure; let s = 0; const atomsIt = AtomSet.atoms(atoms); - const l = Property.createLocation(); + const l = Atom.Location(); while (atomsIt.hasNext) { const a = atomsIt.move(); l.unit = units[Atom.unit(a)]; - l.atomIndex = Atom.index(a); + l.atom = Atom.index(a); s += p(l); } return s; @@ -186,7 +185,7 @@ export namespace PropertyAccess { // while (residuesIt.hasNext) { // const residueSegment = residuesIt.move(); // for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { - // l.atomIndex = OrdSet.getAt(set, j); + // l.atom = OrdSet.getAt(set, j); // s += p(l); // } // } @@ -232,7 +231,7 @@ export namespace PropertyAccess { // for (let j = 0, _j = OrdSet.size(set); j < _j; j++) { // const aI = OrdSet.getAt(set, j); - // l.atomIndex = aI; + // l.atom = aI; // l.residueIndex = residueIndex[aI]; // l.chainIndex = chainIndex[aI]; // s[s.length] = p(l); @@ -251,33 +250,33 @@ export namespace PropertyAccess { console.log(baseline(models[0])); console.log(baselineRaw(models[0])); - console.log(sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.atomIndex))); - console.log(sumPropertySegmented(structures[0], l => l.unit.model.conformation.atomId.value(l.atomIndex))); - //console.log(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.atomIndex))); - console.log(sumPropertyAtomSetIt(structures[0], l => l.unit.model.conformation.atomId.value(l.atomIndex))); - console.log(sumProperty(structures[0], Property.cachedAtomColumn(m => m.conformation.atomId))); + 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))); + //console.log(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.atom))); + console.log(sumPropertyAtomSetIt(structures[0], l => l.unit.model.conformation.atomId.value(l.atom))); + //console.log(sumProperty(structures[0], Property.cachedAtomColumn(m => m.conformation.atomId))); console.log(sumDirect(structures[0])); - console.log('r', sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atomIndex]))); + console.log('r', sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom]))); //const col = models[0].conformation.atomId.value; const suite = new B.Suite(); suite - //.add('test int', () => sumProperty(structures[0], l => col(l.atomIndex))) + //.add('test int', () => sumProperty(structures[0], l => col(l.atom))) // .add('baseline raw', () => baselineRaw(models[0])) - .add('sum residue', () => sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atomIndex]))) + .add('sum residue', () => sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom]))) .add('baseline', () => baseline(models[0])) .add('direct', () => sumDirect(structures[0])) - //.add('normal int', () => sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.atomIndex))) - //.add('atom set it int', () => sumPropertyAtomSetIt(structures[0], l => l.unit.conformation.atomId.value(l.atomIndex))) - // .add('segmented faster int', () => sumPropertySegmented(structures[0], l => l.unit.conformation.atomId.value(l.atomIndex))) - // .add('faster int', () => sumProperty(structures[0], l => l.unit.conformation.atomId.value(l.atomIndex))) - .add('segmented faster _x', () => sumPropertySegmented(structures[0], l => l.unit.conformation.__x[l.atomIndex])) - .add('faster _x', () => sumProperty(structures[0], l => l.unit.conformation.__x[l.atomIndex] + l.unit.conformation.__y[l.atomIndex] + l.unit.conformation.__z[l.atomIndex])) - //.add('segmented mut faster int', () => sumPropertySegmentedMutable(structures[0], l => l.unit.conformation.atomId.value(l.atomIndex))) - //.add('normal shortcut int', () => sumProperty(structures[0], l => l.conformation.atomId.value(l.atomIndex))) + //.add('normal int', () => sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.atom))) + //.add('atom set it int', () => sumPropertyAtomSetIt(structures[0], l => l.unit.conformation.atomId.value(l.atom))) + // .add('segmented faster int', () => sumPropertySegmented(structures[0], l => l.unit.conformation.atomId.value(l.atom))) + // .add('faster int', () => sumProperty(structures[0], l => l.unit.conformation.atomId.value(l.atom))) + .add('segmented faster _x', () => sumPropertySegmented(structures[0], l => l.unit.conformation.__x[l.atom])) + .add('faster _x', () => sumProperty(structures[0], l => l.unit.conformation.__x[l.atom] + l.unit.conformation.__y[l.atom] + l.unit.conformation.__z[l.atom])) + //.add('segmented mut faster int', () => sumPropertySegmentedMutable(structures[0], l => l.unit.conformation.atomId.value(l.atom))) + //.add('normal shortcut int', () => sumProperty(structures[0], l => l.conformation.atomId.value(l.atom))) //.add('cached int', () => sumProperty(structures[0], Property.cachedAtomColumn(m => m.conformation.atomId))) - //.add('concat str', () => concatProperty(structures[0], l => l.unit.model.hierarchy.atoms.auth_atom_id.value(l.atomIndex))) + //.add('concat str', () => concatProperty(structures[0], l => l.unit.model.hierarchy.atoms.auth_atom_id.value(l.atom))) //.add('cached concat str', () => concatProperty(structures[0], Property.cachedAtomColumn(m => m.hierarchy.atoms.auth_atom_id))) .on('cycle', (e: any) => console.log(String(e.target))) .run(); -- GitLab