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

tweaking data model

parent 423f9c47
No related branches found
No related tags found
No related merge requests found
...@@ -30,6 +30,15 @@ describe('atom set', () => { ...@@ -30,6 +30,15 @@ describe('atom set', () => {
expect(AtomSet.atomCount(set)).toBe(1); expect(AtomSet.atomCount(set)).toBe(1);
}); });
it('singleton atom', () => {
const set = AtomSet.singleton(p(10, 11), AtomSet.Empty);
expect(setToPairs(set)).toEqual([p(10, 11)]);
expect(AtomSet.atomHas(set, p(10, 11))).toBe(true);
expect(AtomSet.atomHas(set, p(11, 11))).toBe(false);
expect(AtomSet.atomGetAt(set, 0)).toBe(p(10, 11));
expect(AtomSet.atomCount(set)).toBe(1);
});
it('multi', () => { it('multi', () => {
const gen = AtomSet.Generator(); const gen = AtomSet.Generator();
gen.add(1, AtomGroup.createNew(OrderedSet.ofSortedArray([4, 6, 7]))); gen.add(1, AtomGroup.createNew(OrderedSet.ofSortedArray([4, 6, 7])));
......
...@@ -12,7 +12,7 @@ import { OrderedSet, Segmentation } from 'mol-data/int' ...@@ -12,7 +12,7 @@ import { OrderedSet, Segmentation } from 'mol-data/int'
export const all: Query = s => Selection.Singletons(s, s.atoms); export const all: Query = s => Selection.Singletons(s, s.atoms);
export interface AtomGroupsParams { export interface AtomQueryParams {
entityTest: Atom.Predicate, entityTest: Atom.Predicate,
chainTest: Atom.Predicate, chainTest: Atom.Predicate,
residueTest: Atom.Predicate, residueTest: Atom.Predicate,
...@@ -20,11 +20,18 @@ export interface AtomGroupsParams { ...@@ -20,11 +20,18 @@ export interface AtomGroupsParams {
groupBy: Atom.Property<any> groupBy: Atom.Property<any>
} }
export function atoms(params?: Partial<AtomGroupsParams>): Query { export interface AtomGroupsQueryParams extends AtomQueryParams {
groupBy: Atom.Property<any>
}
export function residues(params?: Partial<AtomQueryParams>) { return atoms({ ...params, groupBy: P.residue.key }); }
export function chains(params?: Partial<AtomQueryParams>) { return atoms({ ...params, groupBy: P.chain.key }); }
export function atoms(params?: Partial<AtomGroupsQueryParams>): Query {
if (!params || (!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy)) return all; if (!params || (!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy)) return all;
if (!!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy) return atomGroupsLinear(params.atomTest); if (!!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy) return atomGroupsLinear(params.atomTest);
const normalized: AtomGroupsParams = { const normalized: AtomGroupsQueryParams = {
entityTest: params.entityTest || P.constant.true, entityTest: params.entityTest || P.constant.true,
chainTest: params.chainTest || P.constant.true, chainTest: params.chainTest || P.constant.true,
residueTest: params.residueTest || P.constant.true, residueTest: params.residueTest || P.constant.true,
...@@ -60,7 +67,7 @@ function atomGroupsLinear(atomTest: Atom.Predicate): Query { ...@@ -60,7 +67,7 @@ function atomGroupsLinear(atomTest: Atom.Predicate): Query {
}; };
} }
function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomGroupsParams): Query { function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomGroupsQueryParams): Query {
return structure => { return structure => {
const { atoms, units } = structure; const { atoms, units } = structure;
const unitIds = AtomSet.unitIds(atoms); const unitIds = AtomSet.unitIds(atoms);
...@@ -133,17 +140,16 @@ class LinearGroupingBuilder { ...@@ -133,17 +140,16 @@ class LinearGroupingBuilder {
} }
private fullSelection() { private fullSelection() {
const sets: AtomSet[] = []; const sets: AtomSet[] = new Array(this.builders.length);
for (let i = 0, _i = this.builders.length; i < _i; i++) { for (let i = 0, _i = this.builders.length; i < _i; i++) {
sets[i] = this.builders[i].getSet(); sets[i] = this.builders[i].getSet();
} }
return Selection.Seq(this.structure, sets); return Selection.Sequence(this.structure, sets);
} }
getSelection(): Selection { getSelection(): Selection {
const len = this.builders.length; const len = this.builders.length;
if (len === 0) return Selection.Empty(this.structure); if (len === 0) return Selection.Empty(this.structure);
if (len === 1) return Selection.Singletons(this.structure, this.builders[0].getSet());
if (this.allSingletons()) return this.singletonSelection(); if (this.allSingletons()) return this.singletonSelection();
return this.fullSelection(); return this.fullSelection();
} }
...@@ -151,7 +157,7 @@ class LinearGroupingBuilder { ...@@ -151,7 +157,7 @@ class LinearGroupingBuilder {
constructor(private structure: Structure) { } constructor(private structure: Structure) { }
} }
function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomGroupsParams): Query { function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomGroupsQueryParams): Query {
return structure => { return structure => {
const { atoms, units } = structure; const { atoms, units } = structure;
const unitIds = AtomSet.unitIds(atoms); const unitIds = AtomSet.unitIds(atoms);
......
...@@ -8,17 +8,16 @@ import { HashSet } from 'mol-data/util' ...@@ -8,17 +8,16 @@ import { HashSet } from 'mol-data/util'
import { Structure, AtomSet } from '../structure' import { Structure, AtomSet } from '../structure'
// A selection is a pair of a Structure and a sequence of unique AtomSets // A selection is a pair of a Structure and a sequence of unique AtomSets
type Selection = Selection.Singletons | Selection.Seq type Selection = Selection.Singletons | Selection.Sequence
namespace Selection { namespace Selection {
// If each element of the selection is a singleton, we can use a more efficient representation. // If each element of the selection is a singleton, we can use a more efficient representation.
export interface Singletons { readonly kind: 'singletons', readonly structure: Structure, readonly set: AtomSet } export interface Singletons { readonly kind: 'singletons', readonly structure: Structure, readonly set: AtomSet }
export interface Seq { readonly kind: 'seq', readonly structure: Structure, readonly sets: ReadonlyArray<AtomSet> } export interface Sequence { readonly kind: 'sequence', readonly structure: Structure, readonly sets: ReadonlyArray<AtomSet> }
export function Singletons(structure: Structure, set: AtomSet): Singletons { return { kind: 'singletons', structure, set } } export function Singletons(structure: Structure, set: AtomSet): Singletons { return { kind: 'singletons', structure, set } }
export function Seq(structure: Structure, sets: AtomSet[]): Seq { return { kind: 'seq', structure, sets } } export function Sequence(structure: Structure, sets: AtomSet[]): Sequence { return { kind: 'sequence', structure, sets } }
export function Empty(structure: Structure): Selection { return Sequence(structure, []); };
export function Empty(structure: Structure): Selection { return Seq(structure, []); };
export function isSingleton(s: Selection): s is Singletons { return s.kind === 'singletons'; } export function isSingleton(s: Selection): s is Singletons { return s.kind === 'singletons'; }
export function isEmpty(s: Selection) { return isSingleton(s) ? AtomSet.atomCount(s.set) === 0 : s.sets.length === 0; } export function isEmpty(s: Selection) { return isSingleton(s) ? AtomSet.atomCount(s.set) === 0 : s.sets.length === 0; }
...@@ -37,11 +36,30 @@ namespace Selection { ...@@ -37,11 +36,30 @@ namespace Selection {
export function getAt(sel: Selection, i: number): Structure { export function getAt(sel: Selection, i: number): Structure {
if (isSingleton(sel)) { if (isSingleton(sel)) {
const atom = AtomSet.atomGetAt(sel.set, i); const atom = AtomSet.atomGetAt(sel.set, i);
return Structure.create(sel.structure.units, AtomSet.ofAtoms([atom], sel.structure.atoms)); return Structure.create(sel.structure.units, AtomSet.singleton(atom, sel.structure.atoms));
} }
return Structure.create(sel.structure.units, sel.sets[i]); return Structure.create(sel.structure.units, sel.sets[i]);
} }
export function toStructures(sel: Selection): Structure[] {
const { units } = sel.structure;
if (isSingleton(sel)) {
const ret: Structure[] = new Array(AtomSet.atomCount(sel.set));
const atoms = AtomSet.atoms(sel.set);
let offset = 0;
while (atoms.hasNext) {
const atom = atoms.move();
ret[offset++] = Structure.create(units, AtomSet.singleton(atom, sel.structure.atoms))
}
return ret;
} else {
const { sets } = sel;
const ret: Structure[] = new Array(sets.length);
for (let i = 0, _i = sets.length; i < _i; i++) ret[i] = Structure.create(units, sets[i]);
return ret;
}
}
export interface Builder { export interface Builder {
add(set: AtomSet): void, add(set: AtomSet): void,
getSelection(): Selection getSelection(): Selection
...@@ -50,9 +68,8 @@ namespace Selection { ...@@ -50,9 +68,8 @@ namespace Selection {
function getSelection(structure: Structure, sets: AtomSet[], allSingletons: boolean) { function getSelection(structure: Structure, sets: AtomSet[], allSingletons: boolean) {
const len = sets.length; const len = sets.length;
if (len === 0) return Empty(structure); if (len === 0) return Empty(structure);
if (len === 1) return Singletons(structure, sets[0]);
if (allSingletons) return Singletons(structure, AtomSet.union(sets, structure.atoms)); if (allSingletons) return Singletons(structure, AtomSet.union(sets, structure.atoms));
return Seq(structure, sets); return Sequence(structure, sets);
} }
class LinearBuilderImpl implements Builder { class LinearBuilderImpl implements Builder {
......
...@@ -20,6 +20,10 @@ export function ofAtoms(atoms: ArrayLike<Atom>, template: AtomSetImpl): AtomSetI ...@@ -20,6 +20,10 @@ export function ofAtoms(atoms: ArrayLike<Atom>, template: AtomSetImpl): AtomSetI
return ofAtomsImpl(atoms, template); return ofAtomsImpl(atoms, template);
} }
export function singleton(atom: Atom, template: AtomSetImpl) {
return singletonImpl(atom, template);
}
export function getKeys(set: AtomSetImpl): SortedArray { export function getKeys(set: AtomSetImpl): SortedArray {
return set.keys; return set.keys;
} }
...@@ -358,6 +362,21 @@ function ofAtomsImpl(xs: ArrayLike<Atom>, template: AtomSetImpl) { ...@@ -358,6 +362,21 @@ function ofAtomsImpl(xs: ArrayLike<Atom>, template: AtomSetImpl) {
return generator.getSet(); return generator.getSet();
} }
function singletonImpl(atom: Atom, template: AtomSetImpl) {
const k = Atom.unit(atom), i = Atom.index(atom);
const { groups } = template;
const gs = IntMap.Mutable<AtomGroup>();
if (groups.has(k)) {
const g = groups.get(k);
if (AtomGroup.size(g) === 1 && AtomGroup.getAt(g, 0) === i) {
gs.set(k, g);
return create([k], gs);
}
}
gs.set(k, AtomGroup.createNew(OS.ofSingleton(i)));
return create([k], gs);
}
function getOffsetIndex(xs: ArrayLike<number>, value: number) { function getOffsetIndex(xs: ArrayLike<number>, value: number) {
let min = 0, max = xs.length - 1; let min = 0, max = xs.length - 1;
while (min < max) { while (min < max) {
......
...@@ -15,6 +15,7 @@ namespace AtomSet { ...@@ -15,6 +15,7 @@ namespace AtomSet {
export const Empty: AtomSet = Impl.Empty as any; export const Empty: AtomSet = Impl.Empty as any;
export const ofAtoms: (atoms: ArrayLike<Atom>, template: AtomSet) => AtomSet = Impl.ofAtoms as any; export const ofAtoms: (atoms: ArrayLike<Atom>, template: AtomSet) => AtomSet = Impl.ofAtoms as any;
export const singleton: (atom: Atom, template: AtomSet) => AtomSet = Impl.singleton as any;
export const unitCount: (set: AtomSet) => number = Impl.keyCount as any; export const unitCount: (set: AtomSet) => number = Impl.keyCount as any;
export const unitIds: (set: AtomSet) => SortedArray = Impl.getKeys as any; export const unitIds: (set: AtomSet) => SortedArray = Impl.getKeys as any;
......
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