Explorar o código

Merge branch 'master' into gl-geo, changed Location.atom to .element

# Conflicts:
#	src/mol-io/common/binary-cif/array-encoder.ts
#	src/perf-tests/chunked-array-vs-native.ts
Alexander Rose %!s(int64=7) %!d(string=hai) anos
pai
achega
5d342a3040
Modificáronse 30 ficheiros con 739 adicións e 685 borrados
  1. 9 5
      src/apps/render-test/state.ts
  2. 11 12
      src/mol-geo/representation/structure/index.ts
  3. 9 9
      src/mol-geo/representation/structure/spacefill.ts
  4. 2 1
      src/mol-io/common/binary-cif/array-encoder.ts
  5. 116 116
      src/mol-model/structure/_spec/atom-set.spec.ts
  6. 4 4
      src/mol-model/structure/export/mmcif.ts
  7. 2 0
      src/mol-model/structure/model/formats/gro.ts
  8. 2 0
      src/mol-model/structure/model/formats/mmcif.ts
  9. 2 0
      src/mol-model/structure/model/model.ts
  10. 15 0
      src/mol-model/structure/model/properties/coarse-grained.ts
  11. 40 40
      src/mol-model/structure/query/generators.ts
  12. 9 9
      src/mol-model/structure/query/predicates.ts
  13. 45 41
      src/mol-model/structure/query/properties.ts
  14. 23 23
      src/mol-model/structure/query/selection.ts
  15. 4 4
      src/mol-model/structure/structure.ts
  16. 0 40
      src/mol-model/structure/structure/atom.ts
  17. 0 71
      src/mol-model/structure/structure/atom/group.ts
  18. 0 60
      src/mol-model/structure/structure/atom/set.ts
  19. 40 0
      src/mol-model/structure/structure/element.ts
  20. 71 0
      src/mol-model/structure/structure/element/group.ts
  21. 0 0
      src/mol-model/structure/structure/element/impl/properties.ts
  22. 15 15
      src/mol-model/structure/structure/element/impl/set-builder.ts
  23. 80 80
      src/mol-model/structure/structure/element/impl/set.ts
  24. 60 0
      src/mol-model/structure/structure/element/set.ts
  25. 24 24
      src/mol-model/structure/structure/structure.ts
  26. 4 4
      src/mol-model/structure/structure/symmetry.ts
  27. 56 31
      src/mol-model/structure/structure/unit.ts
  28. 7 7
      src/perf-tests/chunked-array-vs-native.ts
  29. 10 10
      src/perf-tests/sets.ts
  30. 79 79
      src/perf-tests/structure.ts

+ 9 - 5
src/apps/render-test/state.ts

@@ -15,7 +15,7 @@ import Spacefill from 'mol-geo/representation/structure/spacefill'
 
 
 import CIF from 'mol-io/reader/cif'
 import CIF from 'mol-io/reader/cif'
 import { Run, Progress } from 'mol-task'
 import { Run, Progress } from 'mol-task'
-import { AtomSet, Structure } from 'mol-model/structure'
+import { ElementSet, Structure } from 'mol-model/structure'
 
 
 async function parseCif(data: string|Uint8Array) {
 async function parseCif(data: string|Uint8Array) {
     const comp = CIF.parse(data)
     const comp = CIF.parse(data)
@@ -65,12 +65,15 @@ export default class State {
             position,
             position,
             transform: transformArray1
             transform: transformArray1
         })
         })
+        renderer.add(points)
+
         const mesh = createRenderObject('mesh', {
         const mesh = createRenderObject('mesh', {
             position,
             position,
             normal,
             normal,
             color,
             color,
             transform: transformArray2
             transform: transformArray2
         })
         })
+        renderer.add(mesh)
 
 
         const cylinder = Cylinder({ height: 3, radiusBottom: 0.5, radiusTop: 0.5 })
         const cylinder = Cylinder({ height: 3, radiusBottom: 0.5, radiusTop: 0.5 })
         console.log(cylinder)
         console.log(cylinder)
@@ -92,8 +95,9 @@ export default class State {
             position: ValueCell.create(new Float32Array(box.vertices)),
             position: ValueCell.create(new Float32Array(box.vertices)),
             transform: transformArray1
             transform: transformArray1
         })
         })
+        renderer.add(points2)
 
 
-        let rr = 1;
+        let rr = 0.7;
         function cubesF(x: number, y: number, z: number) {
         function cubesF(x: number, y: number, z: number) {
             return x * x + y * y + z * z - rr * rr;
             return x * x + y * y + z * z - rr * rr;
         }
         }
@@ -115,12 +119,12 @@ export default class State {
 
 
         async function createSpacefills (structure: Structure) {
         async function createSpacefills (structure: Structure) {
             const spacefills: RenderObject[] = []
             const spacefills: RenderObject[] = []
-            const { atoms, units } = structure;
-            const unitIds = AtomSet.unitIds(atoms);
+            const { elements, units } = structure;
+            const unitIds = ElementSet.unitIds(elements);
             for (let i = 0, _i = unitIds.length; i < _i; i++) {
             for (let i = 0, _i = unitIds.length; i < _i; i++) {
                 const unitId = unitIds[i];
                 const unitId = unitIds[i];
                 const unit = units[unitId];
                 const unit = units[unitId];
-                const atomGroup = AtomSet.unitGetByIndex(atoms, i);
+                const atomGroup = ElementSet.unitGetByIndex(elements, i);
 
 
                 const spacefill = Spacefill()
                 const spacefill = Spacefill()
                 spacefills.push(...await Run(spacefill.create(unit, atomGroup), log, 1))
                 spacefills.push(...await Run(spacefill.create(unit, atomGroup), log, 1))

+ 11 - 12
src/mol-geo/representation/structure/index.ts

@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
  */
 
 
-import { AtomGroup, AtomSet, Structure, Unit } from 'mol-model/structure';
+import { ElementGroup, ElementSet, Structure, Unit } from 'mol-model/structure';
 import { RenderObject } from 'mol-gl/renderer';
 import { RenderObject } from 'mol-gl/renderer';
 import { EquivalenceClasses } from 'mol-data/util';
 import { EquivalenceClasses } from 'mol-data/util';
 import { OrderedSet } from 'mol-data/int'
 import { OrderedSet } from 'mol-data/int'
@@ -15,7 +15,7 @@ export interface RepresentationProps {
 }
 }
 
 
 export interface UnitRepresentation {
 export interface UnitRepresentation {
-    create: (unit: Unit, atomGroup: AtomGroup, props?: Partial<RepresentationProps>) => Task<RenderObject[]>,
+    create: (unit: Unit, elementGroup: ElementGroup, props?: Partial<RepresentationProps>) => Task<RenderObject[]>,
     update: (props: RepresentationProps) => boolean,
     update: (props: RepresentationProps) => boolean,
 }
 }
 
 
@@ -25,20 +25,19 @@ export interface UnitRepresentation {
 // }
 // }
 
 
 export class StructureRepresentation {
 export class StructureRepresentation {
-    // map: uint.id -> atomGroup.hashCode[]
     constructor(private repr: UnitRepresentation) {
     constructor(private repr: UnitRepresentation) {
-        // this.repr = props.representation();
+
     }
     }
     create(structure: Structure) {
     create(structure: Structure) {
         return Task.create('S. repr.', async ctx => {
         return Task.create('S. repr.', async ctx => {
 
 
-            const { atoms, units } = structure;
-            const uniqueGroups = EquivalenceClasses<number, AtomGroup>(
-                AtomGroup.hashCode,
-                (a, b) => units[a.id].model.id === units[b.id].model.id && OrderedSet.areEqual(a.atoms, b.atoms));
+            const { elements, units } = structure;
+            const uniqueGroups = EquivalenceClasses<number, ElementGroup>(
+                ElementGroup.hashCode,
+                (a, b) => units[a.id].model.id === units[b.id].model.id && OrderedSet.areEqual(a.elements, b.elements));
 
 
-            for (let i = 0, _i = AtomSet.unitCount(atoms); i < _i; i++) {
-                const group = AtomSet.unitGetByIndex(atoms, i);
+            for (let i = 0, _i = ElementSet.unitCount(elements); i < _i; i++) {
+                const group = ElementSet.unitGetByIndex(elements, i);
                 uniqueGroups.add(group.id, group);
                 uniqueGroups.add(group.id, group);
 
 
             }
             }
@@ -53,8 +52,8 @@ export class StructureRepresentation {
             return true
             return true
         });
         });
     }
     }
-    update(atoms: AtomSet, props: RepresentationProps) {
-        // TODO check model.id, conformation.id, unit.id, atomGroup(.hashCode/.areEqual)
+    update(elements: ElementSet, props: RepresentationProps) {
+        // TODO check model.id, conformation.id, unit.id, elementGroup(.hashCode/.areEqual)
         return false
         return false
     }
     }
 }
 }

+ 9 - 9
src/mol-geo/representation/structure/spacefill.ts

@@ -11,7 +11,7 @@ import { createColorTexture } from 'mol-gl/util';
 import Icosahedron from 'mol-geo/primitive/icosahedron'
 import Icosahedron from 'mol-geo/primitive/icosahedron'
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { OrderedSet } from 'mol-data/int'
 import { OrderedSet } from 'mol-data/int'
-import { Atom, AtomGroup, Unit } from 'mol-model/structure';
+import { Element, ElementGroup, Unit } from 'mol-model/structure';
 import P from 'mol-model/structure/query/properties';
 import P from 'mol-model/structure/query/properties';
 import { RepresentationProps, UnitRepresentation } from './index';
 import { RepresentationProps, UnitRepresentation } from './index';
 import { Task } from 'mol-task'
 import { Task } from 'mol-task'
@@ -25,23 +25,23 @@ export default function Spacefill(): UnitRepresentation {
     // unit: Unit, atomGroup: AtomGroup
     // unit: Unit, atomGroup: AtomGroup
 
 
     return {
     return {
-        create: (unit: Unit, atomGroup: AtomGroup, props: Partial<RepresentationProps> = {}) => Task.create('Spacefill', async ctx => {
-            const atomCount = OrderedSet.size(atomGroup.atoms)
+        create: (unit: Unit, elementGroup: ElementGroup, props: Partial<RepresentationProps> = {}) => Task.create('Spacefill', async ctx => {
+            const elementCount = OrderedSet.size(elementGroup.elements)
 
 
-            const l = Atom.Location();
+            const l = Element.Location();
             l.unit = unit;
             l.unit = unit;
 
 
             const sphere = Icosahedron({ radius: 1, detail: 0 })
             const sphere = Icosahedron({ radius: 1, detail: 0 })
             const vertexCount = sphere.vertices.length / 3
             const vertexCount = sphere.vertices.length / 3
 
 
-            vertices = new Float32Array(atomCount * vertexCount * 3)
-            normals = new Float32Array(atomCount * vertexCount * 3)
+            vertices = new Float32Array(elementCount * vertexCount * 3)
+            normals = new Float32Array(elementCount * vertexCount * 3)
 
 
             const v = Vec3.zero()
             const v = Vec3.zero()
             const m = Mat4.identity()
             const m = Mat4.identity()
 
 
-            for (let i = 0; i < atomCount; i++) {
-                l.atom = OrderedSet.getAt(atomGroup.atoms, i)
+            for (let i = 0; i < elementCount; i++) {
+                l.element = OrderedSet.getAt(elementGroup.elements, i)
 
 
                 v[0] = P.atom.x(l)
                 v[0] = P.atom.x(l)
                 v[1] = P.atom.y(l)
                 v[1] = P.atom.y(l)
@@ -57,7 +57,7 @@ export default function Spacefill(): UnitRepresentation {
                 normals.set(sphere.normals, i * vertexCount * 3);
                 normals.set(sphere.normals, i * vertexCount * 3);
 
 
                 if (i % 100 === 0 && ctx.shouldUpdate) {
                 if (i % 100 === 0 && ctx.shouldUpdate) {
-                    await ctx.update({ message: 'Spacefill', current: i, max: atomCount });
+                    await ctx.update({ message: 'Spacefill', current: i, max: elementCount });
                 }
                 }
             }
             }
 
 

+ 2 - 1
src/mol-io/common/binary-cif/array-encoder.ts

@@ -357,7 +357,8 @@ export namespace ArrayEncoding {
         let map: any = Object.create(null);
         let map: any = Object.create(null);
         let strings: string[] = [];
         let strings: string[] = [];
         let accLength = 0;
         let accLength = 0;
-        let offsets = ChunkedArray.create<number>(s => new Int32Array(s), 1, 1024)
+        let offsets = ChunkedArray.create<number>(s => new Int32Array(s), 1,
+            Math.min(1024, data.length < 32 ? data.length + 1 : Math.round(data.length / 8) + 1));
         let output = new Int32Array(data.length);
         let output = new Int32Array(data.length);
 
 
         ChunkedArray.add(offsets, 0);
         ChunkedArray.add(offsets, 0);

+ 116 - 116
src/mol-model/structure/_spec/atom-set.spec.ts

@@ -5,16 +5,16 @@
  */
  */
 
 
 import { OrderedSet } from 'mol-data/int'
 import { OrderedSet } from 'mol-data/int'
-import AtomSet from '../structure/atom/set'
-import Atom from '../structure/atom'
-import AtomGroup from '../structure/atom/group'
+import ElementSet from '../structure/element/set'
+import Element from '../structure/element'
+import ElementGroup from '../structure/element/group'
 
 
 describe('atom set', () => {
 describe('atom set', () => {
-    const p = (i: number, j: number) => Atom.create(i, j);
+    const p = (i: number, j: number) => Element.create(i, j);
 
 
-    function setToPairs(set: AtomSet): ArrayLike<Atom> {
-        const ret: Atom[] = [];
-        const it = AtomSet.atoms(set);
+    function setToPairs(set: ElementSet): ArrayLike<Element> {
+        const ret: Element[] = [];
+        const it = ElementSet.elements(set);
         while (it.hasNext) {
         while (it.hasNext) {
             ret[ret.length] = it.move();
             ret[ret.length] = it.move();
         }
         }
@@ -22,181 +22,181 @@ describe('atom set', () => {
     }
     }
 
 
     it('singleton pair', () => {
     it('singleton pair', () => {
-        const set = AtomSet.ofAtoms([p(10, 11)], AtomSet.Empty);
+        const set = ElementSet.ofAtoms([p(10, 11)], ElementSet.Empty);
         expect(setToPairs(set)).toEqual([p(10, 11)]);
         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);
+        expect(ElementSet.elementHas(set, p(10, 11))).toBe(true);
+        expect(ElementSet.elementHas(set, p(11, 11))).toBe(false);
+        expect(ElementSet.elementGetAt(set, 0)).toBe(p(10, 11));
+        expect(ElementSet.elementCount(set)).toBe(1);
     });
     });
 
 
     it('singleton atom', () => {
     it('singleton atom', () => {
-        const set = AtomSet.singleton(p(10, 11), AtomSet.Empty);
+        const set = ElementSet.singleton(p(10, 11), ElementSet.Empty);
         expect(setToPairs(set)).toEqual([p(10, 11)]);
         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);
+        expect(ElementSet.elementHas(set, p(10, 11))).toBe(true);
+        expect(ElementSet.elementHas(set, p(11, 11))).toBe(false);
+        expect(ElementSet.elementGetAt(set, 0)).toBe(p(10, 11));
+        expect(ElementSet.elementCount(set)).toBe(1);
     });
     });
 
 
     it('multi', () => {
     it('multi', () => {
-        const gen = AtomSet.Generator();
-        gen.add(1, AtomGroup.createNew(OrderedSet.ofSortedArray([4, 6, 7])));
-        gen.add(3, AtomGroup.createNew(OrderedSet.ofRange(0, 1)));
+        const gen = ElementSet.Generator();
+        gen.add(1, ElementGroup.createNew(OrderedSet.ofSortedArray([4, 6, 7])));
+        gen.add(3, ElementGroup.createNew(OrderedSet.ofRange(0, 1)));
         const set = gen.getSet();
         const set = gen.getSet();
         const ret = [p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)];
         const ret = [p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)];
-        expect(AtomSet.atomCount(set)).toBe(ret.length);
+        expect(ElementSet.elementCount(set)).toBe(ret.length);
         expect(setToPairs(set)).toEqual([p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)]);
         expect(setToPairs(set)).toEqual([p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)]);
-        expect(AtomSet.atomHas(set, p(10, 11))).toBe(false);
-        expect(AtomSet.atomHas(set, p(3, 0))).toBe(true);
-        expect(AtomSet.atomHas(set, p(1, 7))).toBe(true);
-        for (let i = 0; i < AtomSet.atomCount(set); i++) {
-            expect(Atom.areEqual(AtomSet.atomGetAt(set, i), ret[i])).toBe(true);
+        expect(ElementSet.elementHas(set, p(10, 11))).toBe(false);
+        expect(ElementSet.elementHas(set, p(3, 0))).toBe(true);
+        expect(ElementSet.elementHas(set, p(1, 7))).toBe(true);
+        for (let i = 0; i < ElementSet.elementCount(set); i++) {
+            expect(Element.areEqual(ElementSet.elementGetAt(set, i), ret[i])).toBe(true);
         }
         }
     });
     });
 
 
     it('template', () => {
     it('template', () => {
-        const template = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty)
-        const gen = AtomSet.TemplateGenerator(template);
+        const template = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty)
+        const gen = ElementSet.TemplateGenerator(template);
         gen.add(0, OrderedSet.ofSortedArray([1, 2, 6]));
         gen.add(0, OrderedSet.ofSortedArray([1, 2, 6]));
         gen.add(1, OrderedSet.ofSingleton(3));
         gen.add(1, OrderedSet.ofSingleton(3));
         const set = gen.getSet();
         const set = gen.getSet();
 
 
-        expect(AtomSet.unitGetById(set, 0)).toBe(AtomSet.unitGetById(template, 0));
-        expect(AtomSet.unitGetById(set, 1)).toBe(AtomSet.unitGetById(template, 1));
+        expect(ElementSet.unitGetById(set, 0)).toBe(ElementSet.unitGetById(template, 0));
+        expect(ElementSet.unitGetById(set, 1)).toBe(ElementSet.unitGetById(template, 1));
         expect(set).toBe(template);
         expect(set).toBe(template);
     });
     });
 
 
     it('template 1', () => {
     it('template 1', () => {
-        const template = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty)
-        const gen = AtomSet.TemplateGenerator(template);
+        const template = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty)
+        const gen = ElementSet.TemplateGenerator(template);
         gen.add(0, OrderedSet.ofSortedArray([1, 2, 6]));
         gen.add(0, OrderedSet.ofSortedArray([1, 2, 6]));
         gen.add(1, OrderedSet.ofSingleton(4));
         gen.add(1, OrderedSet.ofSingleton(4));
         const set = gen.getSet();
         const set = gen.getSet();
 
 
-        expect(AtomSet.unitGetById(set, 0)).toBe(AtomSet.unitGetById(template, 0));
-        expect(AtomSet.unitGetById(set, 1) === AtomSet.unitGetById(template, 1)).toBe(false);
+        expect(ElementSet.unitGetById(set, 0)).toBe(ElementSet.unitGetById(template, 0));
+        expect(ElementSet.unitGetById(set, 1) === ElementSet.unitGetById(template, 1)).toBe(false);
         expect(set === template).toBe(false);
         expect(set === template).toBe(false);
     });
     });
 
 
     it('template union', () => {
     it('template union', () => {
-        const template = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty)
-
-        const p13 = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const p01 = AtomSet.ofAtoms([p(0, 1)], AtomSet.Empty);
-        const p02 = AtomSet.ofAtoms([p(0, 2)], AtomSet.Empty);
-        const p06 = AtomSet.ofAtoms([p(0, 6)], AtomSet.Empty);
-
-        const u0 = AtomSet.union([p01, p02, p06], template);
-        const u1 = AtomSet.union([p01, p02, p06, p13], template);
-        expect(AtomSet.unitGetById(u0, 0)).toBe(AtomSet.unitGetById(template, 0));
-        expect(AtomSet.unitGetById(u1, 0)).toBe(AtomSet.unitGetById(template, 0));
-        expect(AtomSet.unitGetById(u1, 1)).toBe(AtomSet.unitGetById(template, 1));
+        const template = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty)
+
+        const p13 = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const p01 = ElementSet.ofAtoms([p(0, 1)], ElementSet.Empty);
+        const p02 = ElementSet.ofAtoms([p(0, 2)], ElementSet.Empty);
+        const p06 = ElementSet.ofAtoms([p(0, 6)], ElementSet.Empty);
+
+        const u0 = ElementSet.union([p01, p02, p06], template);
+        const u1 = ElementSet.union([p01, p02, p06, p13], template);
+        expect(ElementSet.unitGetById(u0, 0)).toBe(ElementSet.unitGetById(template, 0));
+        expect(ElementSet.unitGetById(u1, 0)).toBe(ElementSet.unitGetById(template, 0));
+        expect(ElementSet.unitGetById(u1, 1)).toBe(ElementSet.unitGetById(template, 1));
         expect(u1).toBe(template);
         expect(u1).toBe(template);
     });
     });
 
 
     it('element at / index of', () => {
     it('element at / index of', () => {
-        const control: Atom[] = [];
-        const gen = AtomSet.Generator();
+        const control: Element[] = [];
+        const gen = ElementSet.Generator();
         for (let i = 1; i < 10; i++) {
         for (let i = 1; i < 10; i++) {
             const set = [];
             const set = [];
             for (let j = 1; j < 7; j++) {
             for (let j = 1; j < 7; j++) {
                 control[control.length] = p(i * i, j * j + 1);
                 control[control.length] = p(i * i, j * j + 1);
                 set[set.length] = j * j + 1;
                 set[set.length] = j * j + 1;
             }
             }
-            gen.add(i * i, AtomGroup.createNew(OrderedSet.ofSortedArray(set)));
+            gen.add(i * i, ElementGroup.createNew(OrderedSet.ofSortedArray(set)));
         }
         }
         const ms = gen.getSet();
         const ms = gen.getSet();
         for (let i = 0; i < control.length; i++) {
         for (let i = 0; i < control.length; i++) {
-            expect(Atom.areEqual(AtomSet.atomGetAt(ms, i), control[i])).toBe(true);
+            expect(Element.areEqual(ElementSet.elementGetAt(ms, i), control[i])).toBe(true);
         }
         }
 
 
         for (let i = 0; i < control.length; i++) {
         for (let i = 0; i < control.length; i++) {
-            expect(AtomSet.atomIndexOf(ms, control[i])).toBe(i);
+            expect(ElementSet.elementIndexOf(ms, control[i])).toBe(i);
         }
         }
     });
     });
 
 
     it('packed pairs', () => {
     it('packed pairs', () => {
-        const set = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
+        const set = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
         expect(setToPairs(set)).toEqual([p(0, 1), p(0, 2), p(0, 6), p(1, 3)]);
         expect(setToPairs(set)).toEqual([p(0, 1), p(0, 2), p(0, 6), p(1, 3)]);
     });
     });
 
 
     it('equality', () => {
     it('equality', () => {
-        const a = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const b = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const c = AtomSet.ofAtoms([p(1, 3), p(0, 4), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const d = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const e = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const f = AtomSet.ofAtoms([p(3, 3)], AtomSet.Empty);
-
-        expect(AtomSet.areEqual(a, a)).toBe(true);
-        expect(AtomSet.areEqual(a, b)).toBe(true);
-        expect(AtomSet.areEqual(a, c)).toBe(false);
-        expect(AtomSet.areEqual(a, d)).toBe(false);
-        expect(AtomSet.areEqual(d, d)).toBe(true);
-        expect(AtomSet.areEqual(d, e)).toBe(true);
-        expect(AtomSet.areEqual(d, f)).toBe(false);
+        const a = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const b = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const c = ElementSet.ofAtoms([p(1, 3), p(0, 4), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const d = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const e = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const f = ElementSet.ofAtoms([p(3, 3)], ElementSet.Empty);
+
+        expect(ElementSet.areEqual(a, a)).toBe(true);
+        expect(ElementSet.areEqual(a, b)).toBe(true);
+        expect(ElementSet.areEqual(a, c)).toBe(false);
+        expect(ElementSet.areEqual(a, d)).toBe(false);
+        expect(ElementSet.areEqual(d, d)).toBe(true);
+        expect(ElementSet.areEqual(d, e)).toBe(true);
+        expect(ElementSet.areEqual(d, f)).toBe(false);
     });
     });
 
 
     it('are intersecting', () => {
     it('are intersecting', () => {
-        const a = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const b = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const c = AtomSet.ofAtoms([p(1, 3), p(0, 4), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const d = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const e = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const f = AtomSet.ofAtoms([p(3, 3)], AtomSet.Empty);
-        const g = AtomSet.ofAtoms([p(10, 3), p(8, 1), p(7, 6), p(3, 2)], AtomSet.Empty);
-
-        expect(AtomSet.areIntersecting(a, a)).toBe(true);
-        expect(AtomSet.areIntersecting(a, b)).toBe(true);
-        expect(AtomSet.areIntersecting(a, c)).toBe(true);
-        expect(AtomSet.areIntersecting(a, d)).toBe(true);
-        expect(AtomSet.areIntersecting(a, g)).toBe(false);
-        expect(AtomSet.areIntersecting(d, d)).toBe(true);
-        expect(AtomSet.areIntersecting(d, e)).toBe(true);
-        expect(AtomSet.areIntersecting(d, f)).toBe(false);
+        const a = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const b = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const c = ElementSet.ofAtoms([p(1, 3), p(0, 4), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const d = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const e = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const f = ElementSet.ofAtoms([p(3, 3)], ElementSet.Empty);
+        const g = ElementSet.ofAtoms([p(10, 3), p(8, 1), p(7, 6), p(3, 2)], ElementSet.Empty);
+
+        expect(ElementSet.areIntersecting(a, a)).toBe(true);
+        expect(ElementSet.areIntersecting(a, b)).toBe(true);
+        expect(ElementSet.areIntersecting(a, c)).toBe(true);
+        expect(ElementSet.areIntersecting(a, d)).toBe(true);
+        expect(ElementSet.areIntersecting(a, g)).toBe(false);
+        expect(ElementSet.areIntersecting(d, d)).toBe(true);
+        expect(ElementSet.areIntersecting(d, e)).toBe(true);
+        expect(ElementSet.areIntersecting(d, f)).toBe(false);
     });
     });
 
 
     it('intersection', () => {
     it('intersection', () => {
-        const a = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const b = AtomSet.ofAtoms([p(10, 3), p(0, 1), p(0, 6), p(4, 2)], AtomSet.Empty);
-        const c = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const d = AtomSet.ofAtoms([p(2, 3)], AtomSet.Empty);
-        expect(AtomSet.intersect(a, a)).toBe(a);
-        expect(setToPairs(AtomSet.intersect(a, b))).toEqual([p(0, 1), p(0, 6)]);
-        expect(setToPairs(AtomSet.intersect(a, c))).toEqual([p(1, 3)]);
-        expect(setToPairs(AtomSet.intersect(c, d))).toEqual([]);
+        const a = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const b = ElementSet.ofAtoms([p(10, 3), p(0, 1), p(0, 6), p(4, 2)], ElementSet.Empty);
+        const c = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const d = ElementSet.ofAtoms([p(2, 3)], ElementSet.Empty);
+        expect(ElementSet.intersect(a, a)).toBe(a);
+        expect(setToPairs(ElementSet.intersect(a, b))).toEqual([p(0, 1), p(0, 6)]);
+        expect(setToPairs(ElementSet.intersect(a, c))).toEqual([p(1, 3)]);
+        expect(setToPairs(ElementSet.intersect(c, d))).toEqual([]);
     });
     });
 
 
     it('subtract', () => {
     it('subtract', () => {
-        const a = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const a1 = AtomSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], AtomSet.Empty);
-        const b = AtomSet.ofAtoms([p(10, 3), p(0, 1), p(0, 6), p(4, 2)], AtomSet.Empty);
-        const c = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const d = AtomSet.ofAtoms([p(2, 3)], AtomSet.Empty);
-        const e = AtomSet.ofAtoms([p(0, 2)], AtomSet.Empty);
-        expect(setToPairs(AtomSet.subtract(a, a))).toEqual([]);
-        expect(setToPairs(AtomSet.subtract(a, a1))).toEqual([]);
-        expect(setToPairs(AtomSet.subtract(a, b))).toEqual([p(0, 2), p(1, 3)]);
-        expect(setToPairs(AtomSet.subtract(c, d))).toEqual([p(1, 3)]);
-        expect(setToPairs(AtomSet.subtract(a, c))).toEqual([p(0, 1), p(0, 2), p(0, 6)]);
-        expect(setToPairs(AtomSet.subtract(c, a))).toEqual([]);
-        expect(setToPairs(AtomSet.subtract(d, a))).toEqual([p(2, 3)]);
-        expect(setToPairs(AtomSet.subtract(a, e))).toEqual([p(0, 1), p(0, 6), p(1, 3)]);
+        const a = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const a1 = ElementSet.ofAtoms([p(1, 3), p(0, 1), p(0, 6), p(0, 2)], ElementSet.Empty);
+        const b = ElementSet.ofAtoms([p(10, 3), p(0, 1), p(0, 6), p(4, 2)], ElementSet.Empty);
+        const c = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const d = ElementSet.ofAtoms([p(2, 3)], ElementSet.Empty);
+        const e = ElementSet.ofAtoms([p(0, 2)], ElementSet.Empty);
+        expect(setToPairs(ElementSet.subtract(a, a))).toEqual([]);
+        expect(setToPairs(ElementSet.subtract(a, a1))).toEqual([]);
+        expect(setToPairs(ElementSet.subtract(a, b))).toEqual([p(0, 2), p(1, 3)]);
+        expect(setToPairs(ElementSet.subtract(c, d))).toEqual([p(1, 3)]);
+        expect(setToPairs(ElementSet.subtract(a, c))).toEqual([p(0, 1), p(0, 2), p(0, 6)]);
+        expect(setToPairs(ElementSet.subtract(c, a))).toEqual([]);
+        expect(setToPairs(ElementSet.subtract(d, a))).toEqual([p(2, 3)]);
+        expect(setToPairs(ElementSet.subtract(a, e))).toEqual([p(0, 1), p(0, 6), p(1, 3)]);
     });
     });
 
 
     it('union', () => {
     it('union', () => {
-        const a = AtomSet.ofAtoms([p(1, 3), p(0, 1)], AtomSet.Empty);
-        const a1 = AtomSet.ofAtoms([p(1, 3), p(0, 1)], AtomSet.Empty);
-        const b = AtomSet.ofAtoms([p(10, 3), p(0, 1)], AtomSet.Empty);
-        const c = AtomSet.ofAtoms([p(1, 3)], AtomSet.Empty);
-        const d = AtomSet.ofAtoms([p(2, 3)], AtomSet.Empty);
-        expect(AtomSet.union([a], AtomSet.Empty)).toBe(a);
-        expect(AtomSet.union([a, a], AtomSet.Empty)).toBe(a);
-        expect(setToPairs(AtomSet.union([a, a], AtomSet.Empty))).toEqual([p(0, 1), p(1, 3)]);
-        expect(setToPairs(AtomSet.union([a, a1], AtomSet.Empty))).toEqual([p(0, 1), p(1, 3)]);
-        expect(setToPairs(AtomSet.union([a, b], AtomSet.Empty))).toEqual([p(0, 1), p(1, 3), p(10, 3)]);
-        expect(setToPairs(AtomSet.union([c, d], AtomSet.Empty))).toEqual([p(1, 3), p(2, 3)]);
-        expect(setToPairs(AtomSet.union([a, b, c, d], AtomSet.Empty))).toEqual([p(0, 1), p(1, 3), p(2, 3), p(10, 3)]);
+        const a = ElementSet.ofAtoms([p(1, 3), p(0, 1)], ElementSet.Empty);
+        const a1 = ElementSet.ofAtoms([p(1, 3), p(0, 1)], ElementSet.Empty);
+        const b = ElementSet.ofAtoms([p(10, 3), p(0, 1)], ElementSet.Empty);
+        const c = ElementSet.ofAtoms([p(1, 3)], ElementSet.Empty);
+        const d = ElementSet.ofAtoms([p(2, 3)], ElementSet.Empty);
+        expect(ElementSet.union([a], ElementSet.Empty)).toBe(a);
+        expect(ElementSet.union([a, a], ElementSet.Empty)).toBe(a);
+        expect(setToPairs(ElementSet.union([a, a], ElementSet.Empty))).toEqual([p(0, 1), p(1, 3)]);
+        expect(setToPairs(ElementSet.union([a, a1], ElementSet.Empty))).toEqual([p(0, 1), p(1, 3)]);
+        expect(setToPairs(ElementSet.union([a, b], ElementSet.Empty))).toEqual([p(0, 1), p(1, 3), p(10, 3)]);
+        expect(setToPairs(ElementSet.union([c, d], ElementSet.Empty))).toEqual([p(1, 3), p(2, 3)]);
+        expect(setToPairs(ElementSet.union([a, b, c, d], ElementSet.Empty))).toEqual([p(0, 1), p(1, 3), p(2, 3), p(10, 3)]);
     });
     });
 });
 });

+ 4 - 4
src/mol-model/structure/export/mmcif.ts

@@ -9,7 +9,7 @@ import { Column } from 'mol-data/db'
 import Iterator from 'mol-data/iterator'
 import Iterator from 'mol-data/iterator'
 import * as Encoder from 'mol-io/writer/cif'
 import * as Encoder from 'mol-io/writer/cif'
 // import { mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'
 // import { mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'
-import { Structure, Atom, AtomSet } from '../structure'
+import { Structure, Element, ElementSet } from '../structure'
 import { Model } from '../model'
 import { Model } from '../model'
 import P from '../query/properties'
 import P from '../query/properties'
 
 
@@ -68,7 +68,7 @@ function float<K, D = any>(name: string, value: (k: K, d: D) => number, valueKin
 //     //...
 //     //...
 // }
 // }
 
 
-const atom_site: Encoder.CategoryDefinition<Atom.Location> = {
+const atom_site: Encoder.CategoryDefinition<Element.Location> = {
     name: 'atom_site',
     name: 'atom_site',
     fields: [
     fields: [
         str('group_PDB', P.residue.group_PDB),
         str('group_PDB', P.residue.group_PDB),
@@ -113,8 +113,8 @@ function atomSiteProvider({ structure }: Context): Encoder.CategoryInstance {
     return {
     return {
         data: void 0,
         data: void 0,
         definition: atom_site,
         definition: atom_site,
-        keys: () => Structure.atomLocationsTransient(structure),
-        rowCount: AtomSet.atomCount(structure.atoms)
+        keys: () => Structure.elementLocationsTransient(structure),
+        rowCount: ElementSet.elementCount(structure.elements)
     }
     }
 }
 }
 
 

+ 2 - 0
src/mol-model/structure/model/formats/gro.ts

@@ -12,6 +12,7 @@ import Format from '../format'
 import Model from '../model'
 import Model from '../model'
 import * as Hierarchy from '../properties/hierarchy'
 import * as Hierarchy from '../properties/hierarchy'
 import Conformation from '../properties/conformation'
 import Conformation from '../properties/conformation'
+import CoarseGrained from '../properties/coarse-grained'
 import findHierarchyKeys from '../utils/hierarchy-keys'
 import findHierarchyKeys from '../utils/hierarchy-keys'
 import { guessElement } from '../utils/guess-element'
 import { guessElement } from '../utils/guess-element'
 import { ElementSymbol} from '../types'
 import { ElementSymbol} from '../types'
@@ -117,6 +118,7 @@ function createModel(format: gro_Format, modelNum: number, previous?: Model): Mo
         modelNum,
         modelNum,
         hierarchy: { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments },
         hierarchy: { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments },
         conformation: getConformation(structure.atoms),
         conformation: getConformation(structure.atoms),
+        coarseGrained: CoarseGrained.Empty,
         symmetry: { assemblies: [] },
         symmetry: { assemblies: [] },
         atomCount: structure.atoms.count
         atomCount: structure.atoms.count
     };
     };

+ 2 - 0
src/mol-model/structure/model/formats/mmcif.ts

@@ -11,6 +11,7 @@ import Format from '../format'
 import Model from '../model'
 import Model from '../model'
 import * as Hierarchy from '../properties/hierarchy'
 import * as Hierarchy from '../properties/hierarchy'
 import Conformation from '../properties/conformation'
 import Conformation from '../properties/conformation'
+import CoarseGrained from '../properties/coarse-grained'
 import Symmetry from '../properties/symmetry'
 import Symmetry from '../properties/symmetry'
 import findHierarchyKeys from '../utils/hierarchy-keys'
 import findHierarchyKeys from '../utils/hierarchy-keys'
 import { ElementSymbol} from '../types'
 import { ElementSymbol} from '../types'
@@ -111,6 +112,7 @@ function createModel(format: mmCIF_Format, bounds: Interval, previous?: Model):
         modelNum: format.data.atom_site.pdbx_PDB_model_num.value(Interval.start(bounds)),
         modelNum: format.data.atom_site.pdbx_PDB_model_num.value(Interval.start(bounds)),
         hierarchy: { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments },
         hierarchy: { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments },
         conformation: getConformation(format, bounds),
         conformation: getConformation(format, bounds),
+        coarseGrained: CoarseGrained.Empty,
         symmetry: getSymmetry(format),
         symmetry: getSymmetry(format),
         atomCount: Interval.size(bounds)
         atomCount: Interval.size(bounds)
     };
     };

+ 2 - 0
src/mol-model/structure/model/model.ts

@@ -11,6 +11,7 @@ import Hierarchy from './properties/hierarchy'
 import Conformation from './properties/conformation'
 import Conformation from './properties/conformation'
 import Symmetry from './properties/symmetry'
 import Symmetry from './properties/symmetry'
 import Bonds from './properties/bonds'
 import Bonds from './properties/bonds'
+import CoarseGrained from './properties/coarse-grained'
 
 
 import computeBonds from './utils/compute-bonds'
 import computeBonds from './utils/compute-bonds'
 
 
@@ -33,6 +34,7 @@ interface Model extends Readonly<{
     hierarchy: Hierarchy,
     hierarchy: Hierarchy,
     conformation: Conformation,
     conformation: Conformation,
     symmetry: Symmetry,
     symmetry: Symmetry,
+    coarseGrained: CoarseGrained,
 
 
     atomCount: number,
     atomCount: number,
 }> {
 }> {

+ 15 - 0
src/mol-model/structure/model/properties/coarse-grained.ts

@@ -0,0 +1,15 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+interface CoarseGrained {
+    // TODO
+}
+
+namespace CoarseGrained {
+    export const Empty: CoarseGrained = { };
+}
+
+export default CoarseGrained;

+ 40 - 40
src/mol-model/structure/query/generators.ts

@@ -7,21 +7,21 @@
 import Query from './query'
 import Query from './query'
 import Selection from './selection'
 import Selection from './selection'
 import P from './properties'
 import P from './properties'
-import { Structure, AtomSet, Atom } from '../structure'
+import { Structure, ElementSet, Element } from '../structure'
 import { OrderedSet, Segmentation } from 'mol-data/int'
 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.elements);
 
 
 export interface AtomQueryParams {
 export interface AtomQueryParams {
-    entityTest: Atom.Predicate,
-    chainTest: Atom.Predicate,
-    residueTest: Atom.Predicate,
-    atomTest: Atom.Predicate,
-    groupBy: Atom.Property<any>
+    entityTest: Element.Predicate,
+    chainTest: Element.Predicate,
+    residueTest: Element.Predicate,
+    atomTest: Element.Predicate,
+    groupBy: Element.Property<any>
 }
 }
 
 
 export interface AtomGroupsQueryParams extends AtomQueryParams {
 export interface AtomGroupsQueryParams extends AtomQueryParams {
-    groupBy: Atom.Property<any>
+    groupBy: Element.Property<any>
 }
 }
 
 
 export function residues(params?: Partial<AtomQueryParams>) { return atoms({ ...params, groupBy: P.residue.key }); }
 export function residues(params?: Partial<AtomQueryParams>) { return atoms({ ...params, groupBy: P.residue.key }); }
@@ -43,22 +43,22 @@ export function atoms(params?: Partial<AtomGroupsQueryParams>): Query {
     return atomGroupsGrouped(normalized);
     return atomGroupsGrouped(normalized);
 }
 }
 
 
-function atomGroupsLinear(atomTest: Atom.Predicate): Query {
+function atomGroupsLinear(atomTest: Element.Predicate): Query {
     return structure => {
     return structure => {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
-        const l = Atom.Location();
-        const builder = AtomSet.LinearBuilder(atoms);
+        const { elements, units } = structure;
+        const unitIds = ElementSet.unitIds(elements);
+        const l = Element.Location();
+        const builder = ElementSet.LinearBuilder(elements);
 
 
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
             const unitId = unitIds[i];
             const unitId = unitIds[i];
             l.unit = units[unitId];
             l.unit = units[unitId];
-            const set = AtomSet.unitGetByIndex(atoms, i).atoms;
+            const set = ElementSet.unitGetByIndex(elements, i).elements;
 
 
             builder.beginUnit();
             builder.beginUnit();
             for (let j = 0, _j = OrderedSet.size(set); j < _j; j++) {
             for (let j = 0, _j = OrderedSet.size(set); j < _j; j++) {
-                l.atom = OrderedSet.getAt(set, j);
-                if (atomTest(l)) builder.addToUnit(l.atom);
+                l.element = OrderedSet.getAt(set, j);
+                if (atomTest(l)) builder.addToUnit(l.element);
             }
             }
             builder.commitUnit(unitId);
             builder.commitUnit(unitId);
         }
         }
@@ -69,37 +69,37 @@ function atomGroupsLinear(atomTest: Atom.Predicate): Query {
 
 
 function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomGroupsQueryParams): Query {
 function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomGroupsQueryParams): Query {
     return structure => {
     return structure => {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
-        const l = Atom.Location();
-        const builder = AtomSet.LinearBuilder(atoms);
+        const { elements, units } = structure;
+        const unitIds = ElementSet.unitIds(elements);
+        const l = Element.Location();
+        const builder = ElementSet.LinearBuilder(elements);
 
 
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
             const unitId = unitIds[i];
             const unitId = unitIds[i];
             const unit = units[unitId];
             const unit = units[unitId];
             l.unit = unit;
             l.unit = unit;
-            const set = AtomSet.unitGetByIndex(atoms, i).atoms;
+            const set = ElementSet.unitGetByIndex(elements, i).elements;
 
 
             builder.beginUnit();
             builder.beginUnit();
             const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set);
             const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set);
             const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set);
             const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set);
             while (chainsIt.hasNext) {
             while (chainsIt.hasNext) {
                 const chainSegment = chainsIt.move();
                 const chainSegment = chainsIt.move();
-                l.atom = OrderedSet.getAt(set, chainSegment.start);
+                l.element = OrderedSet.getAt(set, chainSegment.start);
                 // test entity and chain
                 // test entity and chain
                 if (!entityTest(l) || !chainTest(l)) continue;
                 if (!entityTest(l) || !chainTest(l)) continue;
 
 
                 residuesIt.setSegment(chainSegment);
                 residuesIt.setSegment(chainSegment);
                 while (residuesIt.hasNext) {
                 while (residuesIt.hasNext) {
                     const residueSegment = residuesIt.move();
                     const residueSegment = residuesIt.move();
-                    l.atom = OrderedSet.getAt(set, residueSegment.start);
+                    l.element = OrderedSet.getAt(set, residueSegment.start);
 
 
                     // test residue
                     // test residue
                     if (!residueTest(l)) continue;
                     if (!residueTest(l)) continue;
 
 
                     for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
                     for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
-                        l.atom = OrderedSet.getAt(set, j);
-                        if (atomTest(l)) builder.addToUnit(l.atom);
+                        l.element = OrderedSet.getAt(set, j);
+                        if (atomTest(l)) builder.addToUnit(l.element);
                     }
                     }
                 }
                 }
             }
             }
@@ -111,13 +111,13 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
 }
 }
 
 
 class LinearGroupingBuilder {
 class LinearGroupingBuilder {
-    private builders: AtomSet.Builder[] = [];
-    private builderMap = new Map<string, AtomSet.Builder>();
+    private builders: ElementSet.Builder[] = [];
+    private builderMap = new Map<string, ElementSet.Builder>();
 
 
     add(key: any, unit: number, atom: number) {
     add(key: any, unit: number, atom: number) {
         let b = this.builderMap.get(key);
         let b = this.builderMap.get(key);
         if (!b) {
         if (!b) {
-            b = AtomSet.LinearBuilder(this.structure.atoms);
+            b = ElementSet.LinearBuilder(this.structure.elements);
             this.builders[this.builders.length] = b;
             this.builders[this.builders.length] = b;
             this.builderMap.set(key, b);
             this.builderMap.set(key, b);
         }
         }
@@ -126,21 +126,21 @@ class LinearGroupingBuilder {
 
 
     private allSingletons() {
     private allSingletons() {
         for (let i = 0, _i = this.builders.length; i < _i; i++) {
         for (let i = 0, _i = this.builders.length; i < _i; i++) {
-            if (this.builders[i].atomCount > 1) return false;
+            if (this.builders[i].elementCount > 1) return false;
         }
         }
         return true;
         return true;
     }
     }
 
 
     private singletonSelection(): Selection {
     private singletonSelection(): Selection {
-        const atoms: Atom[] = Atom.createEmptyArray(this.builders.length);
+        const atoms: Element[] = Element.createEmptyArray(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++) {
             atoms[i] = this.builders[i].singleton();
             atoms[i] = this.builders[i].singleton();
         }
         }
-        return Selection.Singletons(this.structure, AtomSet.ofAtoms(atoms, this.structure.atoms));
+        return Selection.Singletons(this.structure, ElementSet.ofAtoms(atoms, this.structure.elements));
     }
     }
 
 
     private fullSelection() {
     private fullSelection() {
-        const sets: AtomSet[] = new Array(this.builders.length);
+        const sets: ElementSet[] = 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();
         }
         }
@@ -159,36 +159,36 @@ class LinearGroupingBuilder {
 
 
 function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomGroupsQueryParams): Query {
 function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomGroupsQueryParams): Query {
     return structure => {
     return structure => {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
-        const l = Atom.Location();
+        const { elements, units } = structure;
+        const unitIds = ElementSet.unitIds(elements);
+        const l = Element.Location();
         const builder = new LinearGroupingBuilder(structure);
         const builder = new LinearGroupingBuilder(structure);
 
 
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
             const unitId = unitIds[i];
             const unitId = unitIds[i];
             const unit = units[unitId];
             const unit = units[unitId];
             l.unit = unit;
             l.unit = unit;
-            const set = AtomSet.unitGetByIndex(atoms, i).atoms;
+            const set = ElementSet.unitGetByIndex(elements, i).elements;
 
 
             const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set);
             const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set);
             const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set);
             const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set);
             while (chainsIt.hasNext) {
             while (chainsIt.hasNext) {
                 const chainSegment = chainsIt.move();
                 const chainSegment = chainsIt.move();
-                l.atom = OrderedSet.getAt(set, chainSegment.start);
+                l.element = OrderedSet.getAt(set, chainSegment.start);
                 // test entity and chain
                 // test entity and chain
                 if (!entityTest(l) || !chainTest(l)) continue;
                 if (!entityTest(l) || !chainTest(l)) continue;
 
 
                 residuesIt.setSegment(chainSegment);
                 residuesIt.setSegment(chainSegment);
                 while (residuesIt.hasNext) {
                 while (residuesIt.hasNext) {
                     const residueSegment = residuesIt.move();
                     const residueSegment = residuesIt.move();
-                    l.atom = OrderedSet.getAt(set, residueSegment.start);
+                    l.element = OrderedSet.getAt(set, residueSegment.start);
 
 
                     // test residue
                     // test residue
                     if (!residueTest(l)) continue;
                     if (!residueTest(l)) continue;
 
 
                     for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
                     for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
-                        l.atom = OrderedSet.getAt(set, j);
-                        if (atomTest(l)) builder.add(groupBy(l), unitId, l.atom);
+                        l.element = OrderedSet.getAt(set, j);
+                        if (atomTest(l)) builder.add(groupBy(l), unitId, l.element);
                     }
                     }
                 }
                 }
             }
             }

+ 9 - 9
src/mol-model/structure/query/predicates.ts

@@ -4,20 +4,20 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author David Sehnal <david.sehnal@gmail.com>
  */
  */
 
 
-import { Atom } from '../structure'
+import { Element } from '../structure'
 import P from './properties'
 import P from './properties'
 
 
 namespace Predicates {
 namespace Predicates {
     export interface SetLike<A> { has(v: A): boolean }
     export interface SetLike<A> { has(v: A): boolean }
     function isSetLike<A>(x: any): x is SetLike<A> { return !!x && !!x.has }
     function isSetLike<A>(x: any): x is SetLike<A> { return !!x && !!x.has }
 
 
-    export function eq<A>(p: Atom.Property<A>, value: A): Atom.Predicate { return l => p(l) === value; }
-    export function lt<A>(p: Atom.Property<A>, value: A): Atom.Predicate { return l => p(l) < value; }
-    export function lte<A>(p: Atom.Property<A>, value: A): Atom.Predicate { return l => p(l) <= value; }
-    export function gt<A>(p: Atom.Property<A>, value: A): Atom.Predicate { return l => p(l) > value; }
-    export function gte<A>(p: Atom.Property<A>, value: A): Atom.Predicate { return l => p(l) >= value; }
+    export function eq<A>(p: Element.Property<A>, value: A): Element.Predicate { return l => p(l) === value; }
+    export function lt<A>(p: Element.Property<A>, value: A): Element.Predicate { return l => p(l) < value; }
+    export function lte<A>(p: Element.Property<A>, value: A): Element.Predicate { return l => p(l) <= value; }
+    export function gt<A>(p: Element.Property<A>, value: A): Element.Predicate { return l => p(l) > value; }
+    export function gte<A>(p: Element.Property<A>, value: A): Element.Predicate { return l => p(l) >= value; }
 
 
-    export function inSet<A>(p: Atom.Property<A>, values: SetLike<A> | ArrayLike<A>): Atom.Predicate {
+    export function inSet<A>(p: Element.Property<A>, values: SetLike<A> | ArrayLike<A>): Element.Predicate {
         if (isSetLike(values)) {
         if (isSetLike(values)) {
             return l => values.has(p(l));
             return l => values.has(p(l));
         } else {
         } else {
@@ -28,7 +28,7 @@ namespace Predicates {
         }
         }
     }
     }
 
 
-    export function and(...ps: Atom.Predicate[]): Atom.Predicate {
+    export function and(...ps: Element.Predicate[]): Element.Predicate {
         switch (ps.length) {
         switch (ps.length) {
             case 0: return P.constant.true;
             case 0: return P.constant.true;
             case 1: return ps[0];
             case 1: return ps[0];
@@ -62,7 +62,7 @@ namespace Predicates {
         }
         }
     }
     }
 
 
-    export function or(...ps: Atom.Predicate[]): Atom.Predicate {
+    export function or(...ps: Element.Predicate[]): Element.Predicate {
         switch (ps.length) {
         switch (ps.length) {
             case 0: return P.constant.false;
             case 0: return P.constant.false;
             case 1: return ps[0];
             case 1: return ps[0];

+ 45 - 41
src/mol-model/structure/query/properties.ts

@@ -4,72 +4,76 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author David Sehnal <david.sehnal@gmail.com>
  */
  */
 
 
-import { Atom } from '../structure'
+import { Element, Unit } from '../structure'
 
 
 const constant = {
 const constant = {
-    true: Atom.property(l => true),
-    false: Atom.property(l => false),
-    zero: Atom.property(l => 0)
+    true: Element.property(l => true),
+    false: Element.property(l => false),
+    zero: Element.property(l => 0)
+}
+
+function notAtomic(): never {
+    throw 'Property only available for atomic models.';
 }
 }
 
 
 const atom = {
 const atom = {
-    key: Atom.property(l => l.atom),
+    key: Element.property(l => l.element),
 
 
     // Conformation
     // Conformation
-    x: Atom.property(l => l.unit.x(l.atom)),
-    y: Atom.property(l => l.unit.y(l.atom)),
-    z: Atom.property(l => l.unit.z(l.atom)),
-    id: Atom.property(l => l.unit.conformation.atomId.value(l.atom)),
-    occupancy: Atom.property(l => l.unit.conformation.occupancy.value(l.atom)),
-    B_iso_or_equiv: Atom.property(l => l.unit.conformation.B_iso_or_equiv.value(l.atom)),
+    x: Element.property(l => l.unit.x(l.element)),
+    y: Element.property(l => l.unit.y(l.element)),
+    z: Element.property(l => l.unit.z(l.element)),
+    id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.conformation.atomId.value(l.element)),
+    occupancy: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.conformation.occupancy.value(l.element)),
+    B_iso_or_equiv: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.conformation.B_iso_or_equiv.value(l.element)),
 
 
     // Hierarchy
     // Hierarchy
-    type_symbol: Atom.property(l => l.unit.hierarchy.atoms.type_symbol.value(l.atom)),
-    label_atom_id: Atom.property(l => l.unit.hierarchy.atoms.label_atom_id.value(l.atom)),
-    auth_atom_id: Atom.property(l => l.unit.hierarchy.atoms.auth_atom_id.value(l.atom)),
-    label_alt_id: Atom.property(l => l.unit.hierarchy.atoms.label_alt_id.value(l.atom)),
-    pdbx_formal_charge: Atom.property(l => l.unit.hierarchy.atoms.pdbx_formal_charge.value(l.atom))
+    type_symbol: Element.property(l => l.unit.hierarchy.atoms.type_symbol.value(l.element)),
+    label_atom_id: Element.property(l => l.unit.hierarchy.atoms.label_atom_id.value(l.element)),
+    auth_atom_id: Element.property(l => l.unit.hierarchy.atoms.auth_atom_id.value(l.element)),
+    label_alt_id: Element.property(l => l.unit.hierarchy.atoms.label_alt_id.value(l.element)),
+    pdbx_formal_charge: Element.property(l => l.unit.hierarchy.atoms.pdbx_formal_charge.value(l.element))
 }
 }
 
 
 const residue = {
 const residue = {
-    key: Atom.property(l => l.unit.hierarchy.residueKey.value(l.unit.residueIndex[l.atom])),
-
-    group_PDB: Atom.property(l => l.unit.hierarchy.residues.group_PDB.value(l.unit.residueIndex[l.atom])),
-    label_comp_id: Atom.property(l => l.unit.hierarchy.residues.label_comp_id.value(l.unit.residueIndex[l.atom])),
-    auth_comp_id: Atom.property(l => l.unit.hierarchy.residues.auth_comp_id.value(l.unit.residueIndex[l.atom])),
-    label_seq_id: Atom.property(l => l.unit.hierarchy.residues.label_seq_id.value(l.unit.residueIndex[l.atom])),
-    auth_seq_id: Atom.property(l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])),
-    pdbx_PDB_ins_code: Atom.property(l => l.unit.hierarchy.residues.pdbx_PDB_ins_code.value(l.unit.residueIndex[l.atom]))
+    key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residueKey.value(l.unit.residueIndex[l.element])),
+
+    group_PDB: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.group_PDB.value(l.unit.residueIndex[l.element])),
+    label_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.label_comp_id.value(l.unit.residueIndex[l.element])),
+    auth_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.auth_comp_id.value(l.unit.residueIndex[l.element])),
+    label_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.label_seq_id.value(l.unit.residueIndex[l.element])),
+    auth_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.element])),
+    pdbx_PDB_ins_code: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.pdbx_PDB_ins_code.value(l.unit.residueIndex[l.element]))
 }
 }
 
 
 const chain = {
 const chain = {
-    key: Atom.property(l => l.unit.hierarchy.chainKey.value(l.unit.chainIndex[l.atom])),
+    key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chainKey.value(l.unit.chainIndex[l.element])),
 
 
-    label_asym_id: Atom.property(l => l.unit.hierarchy.chains.label_asym_id.value(l.unit.chainIndex[l.atom])),
-    auth_asym_id: Atom.property(l => l.unit.hierarchy.chains.auth_asym_id.value(l.unit.chainIndex[l.atom])),
-    label_entity_id: Atom.property(l => l.unit.hierarchy.chains.label_entity_id.value(l.unit.chainIndex[l.atom]))
+    label_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chains.label_asym_id.value(l.unit.chainIndex[l.element])),
+    auth_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chains.auth_asym_id.value(l.unit.chainIndex[l.element])),
+    label_entity_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chains.label_entity_id.value(l.unit.chainIndex[l.element]))
 }
 }
 
 
-function eK(l: Atom.Location) { return l.unit.hierarchy.entityKey.value(l.unit.chainIndex[l.atom]); }
+function eK(l: Element.Location) { return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.entityKey.value(l.unit.chainIndex[l.element]); }
 
 
 const entity = {
 const entity = {
     key: eK,
     key: eK,
 
 
-    id: Atom.property(l => l.unit.hierarchy.entities.id.value(eK(l))),
-    type: Atom.property(l => l.unit.hierarchy.entities.type.value(eK(l))),
-    src_method: Atom.property(l => l.unit.hierarchy.entities.src_method.value(eK(l))),
-    pdbx_description: Atom.property(l => l.unit.hierarchy.entities.pdbx_description.value(eK(l))),
-    formula_weight: Atom.property(l => l.unit.hierarchy.entities.formula_weight.value(eK(l))),
-    pdbx_number_of_molecules: Atom.property(l => l.unit.hierarchy.entities.pdbx_number_of_molecules.value(eK(l))),
-    details: Atom.property(l => l.unit.hierarchy.entities.details.value(eK(l))),
-    pdbx_mutation: Atom.property(l => l.unit.hierarchy.entities.pdbx_mutation.value(eK(l))),
-    pdbx_fragment: Atom.property(l => l.unit.hierarchy.entities.pdbx_fragment.value(eK(l))),
-    pdbx_ec: Atom.property(l => l.unit.hierarchy.entities.pdbx_ec.value(eK(l)))
+    id: Element.property(l => l.unit.hierarchy.entities.id.value(eK(l))),
+    type: Element.property(l => l.unit.hierarchy.entities.type.value(eK(l))),
+    src_method: Element.property(l => l.unit.hierarchy.entities.src_method.value(eK(l))),
+    pdbx_description: Element.property(l => l.unit.hierarchy.entities.pdbx_description.value(eK(l))),
+    formula_weight: Element.property(l => l.unit.hierarchy.entities.formula_weight.value(eK(l))),
+    pdbx_number_of_molecules: Element.property(l => l.unit.hierarchy.entities.pdbx_number_of_molecules.value(eK(l))),
+    details: Element.property(l => l.unit.hierarchy.entities.details.value(eK(l))),
+    pdbx_mutation: Element.property(l => l.unit.hierarchy.entities.pdbx_mutation.value(eK(l))),
+    pdbx_fragment: Element.property(l => l.unit.hierarchy.entities.pdbx_fragment.value(eK(l))),
+    pdbx_ec: Element.property(l => l.unit.hierarchy.entities.pdbx_ec.value(eK(l)))
 }
 }
 
 
 const unit = {
 const unit = {
-    operator_name: Atom.property(l => l.unit.operator.name),
-    model_num: Atom.property(l => l.unit.model.modelNum)
+    operator_name: Element.property(l => l.unit.operator.name),
+    model_num: Element.property(l => l.unit.model.modelNum)
 }
 }
 
 
 const Properties = {
 const Properties = {

+ 23 - 23
src/mol-model/structure/query/selection.ts

@@ -5,38 +5,38 @@
  */
  */
 
 
 import { HashSet } from 'mol-data/generic'
 import { HashSet } from 'mol-data/generic'
-import { Structure, AtomSet } from '../structure'
+import { Structure, ElementSet } 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.Sequence
 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 Sequence { readonly kind: 'sequence', readonly structure: Structure, readonly sets: ReadonlyArray<AtomSet> }
+    export interface Singletons { readonly kind: 'singletons', readonly structure: Structure, readonly set: ElementSet }
+    export interface Sequence { readonly kind: 'sequence', readonly structure: Structure, readonly sets: ReadonlyArray<ElementSet> }
 
 
-    export function Singletons(structure: Structure, set: AtomSet): Singletons { return { kind: 'singletons', structure, set } }
-    export function Sequence(structure: Structure, sets: AtomSet[]): Sequence { return { kind: 'sequence', structure, sets } }
+    export function Singletons(structure: Structure, set: ElementSet): Singletons { return { kind: 'singletons', structure, set } }
+    export function Sequence(structure: Structure, sets: ElementSet[]): Sequence { return { kind: 'sequence', structure, sets } }
     export function Empty(structure: Structure): Selection { return Sequence(structure, []); };
     export function Empty(structure: Structure): Selection { return Sequence(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) ? ElementSet.elementCount(s.set) === 0 : s.sets.length === 0; }
 
 
     export function structureCount(sel: Selection) {
     export function structureCount(sel: Selection) {
-        if (isSingleton(sel)) return AtomSet.atomCount(sel.set);
+        if (isSingleton(sel)) return ElementSet.elementCount(sel.set);
         return sel.sets.length;
         return sel.sets.length;
     }
     }
 
 
     export function unionStructure(sel: Selection): Structure {
     export function unionStructure(sel: Selection): Structure {
         if (isEmpty(sel)) return Structure.Empty(sel.structure.units);
         if (isEmpty(sel)) return Structure.Empty(sel.structure.units);
         if (isSingleton(sel)) return Structure.create(sel.structure.units, sel.set);
         if (isSingleton(sel)) return Structure.create(sel.structure.units, sel.set);
-        return Structure.create(sel.structure.units, AtomSet.union(sel.sets, sel.structure.atoms));
+        return Structure.create(sel.structure.units, ElementSet.union(sel.sets, sel.structure.elements));
     }
     }
 
 
     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);
-            return Structure.create(sel.structure.units, AtomSet.singleton(atom, sel.structure.atoms));
+            const atom = ElementSet.elementGetAt(sel.set, i);
+            return Structure.create(sel.structure.units, ElementSet.singleton(atom, sel.structure.elements));
         }
         }
         return Structure.create(sel.structure.units, sel.sets[i]);
         return Structure.create(sel.structure.units, sel.sets[i]);
     }
     }
@@ -44,12 +44,12 @@ namespace Selection {
     export function toStructures(sel: Selection): Structure[] {
     export function toStructures(sel: Selection): Structure[] {
         const { units } = sel.structure;
         const { units } = sel.structure;
         if (isSingleton(sel)) {
         if (isSingleton(sel)) {
-            const ret: Structure[] = new Array(AtomSet.atomCount(sel.set));
-            const atoms = AtomSet.atoms(sel.set);
+            const ret: Structure[] = new Array(ElementSet.elementCount(sel.set));
+            const atoms = ElementSet.elements(sel.set);
             let offset = 0;
             let offset = 0;
             while (atoms.hasNext) {
             while (atoms.hasNext) {
                 const atom = atoms.move();
                 const atom = atoms.move();
-                ret[offset++] = Structure.create(units, AtomSet.singleton(atom, sel.structure.atoms))
+                ret[offset++] = Structure.create(units, ElementSet.singleton(atom, sel.structure.elements))
             }
             }
             return ret;
             return ret;
         } else {
         } else {
@@ -61,23 +61,23 @@ namespace Selection {
     }
     }
 
 
     export interface Builder {
     export interface Builder {
-        add(set: AtomSet): void,
+        add(set: ElementSet): void,
         getSelection(): Selection
         getSelection(): Selection
     }
     }
 
 
-    function getSelection(structure: Structure, sets: AtomSet[], allSingletons: boolean) {
+    function getSelection(structure: Structure, sets: ElementSet[], allSingletons: boolean) {
         const len = sets.length;
         const len = sets.length;
         if (len === 0) return Empty(structure);
         if (len === 0) return Empty(structure);
-        if (allSingletons) return Singletons(structure, AtomSet.union(sets, structure.atoms));
+        if (allSingletons) return Singletons(structure, ElementSet.union(sets, structure.elements));
         return Sequence(structure, sets);
         return Sequence(structure, sets);
     }
     }
 
 
     class LinearBuilderImpl implements Builder {
     class LinearBuilderImpl implements Builder {
-        private sets: AtomSet[] = [];
+        private sets: ElementSet[] = [];
         private allSingletons = true;
         private allSingletons = true;
 
 
-        add(atoms: AtomSet) {
-            const atomCount = AtomSet.atomCount(atoms);
+        add(atoms: ElementSet) {
+            const atomCount = ElementSet.elementCount(atoms);
             if (atomCount === 0) return;
             if (atomCount === 0) return;
             this.sets[this.sets.length] = atoms;
             this.sets[this.sets.length] = atoms;
             if (atomCount !== 1) this.allSingletons = false;
             if (atomCount !== 1) this.allSingletons = false;
@@ -89,12 +89,12 @@ namespace Selection {
     }
     }
 
 
     class HashBuilderImpl implements Builder {
     class HashBuilderImpl implements Builder {
-        private sets: AtomSet[] = [];
+        private sets: ElementSet[] = [];
         private allSingletons = true;
         private allSingletons = true;
-        private uniqueSets = HashSet(AtomSet.hashCode, AtomSet.areEqual);
+        private uniqueSets = HashSet(ElementSet.hashCode, ElementSet.areEqual);
 
 
-        add(atoms: AtomSet) {
-            const atomCount = AtomSet.atomCount(atoms);
+        add(atoms: ElementSet) {
+            const atomCount = ElementSet.elementCount(atoms);
             if (atomCount === 0 || !this.uniqueSets.add(atoms)) return;
             if (atomCount === 0 || !this.uniqueSets.add(atoms)) return;
             this.sets[this.sets.length] = atoms;
             this.sets[this.sets.length] = atoms;
             if (atomCount !== 1) this.allSingletons = false;
             if (atomCount !== 1) this.allSingletons = false;

+ 4 - 4
src/mol-model/structure/structure.ts

@@ -4,11 +4,11 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author David Sehnal <david.sehnal@gmail.com>
  */
  */
 
 
-import Atom from './structure/atom'
-import AtomSet from './structure/atom/set'
-import AtomGroup from './structure/atom/group'
+import Element from './structure/element'
+import ElementSet from './structure/element/set'
+import ElementGroup from './structure/element/group'
 import Structure from './structure/structure'
 import Structure from './structure/structure'
 import Unit from './structure/unit'
 import Unit from './structure/unit'
 import Symmetry from './structure/symmetry'
 import Symmetry from './structure/symmetry'
 
 
-export { Atom, AtomSet, AtomGroup, Structure, Unit, Symmetry }
+export { Element, ElementSet, ElementGroup, Structure, Unit, Symmetry }

+ 0 - 40
src/mol-model/structure/structure/atom.ts

@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import { Tuple } from 'mol-data/int'
-import Unit from './unit'
-import Structure from './structure'
-
-/** Atom pointer */
-interface Atom { '@type': Tuple['@type'] }
-
-namespace Atom {
-    export const Zero: Atom = Tuple.Zero;
-    export const create: (unit: number, index: number) => Atom = Tuple.create;
-    export const is: (x: any) => x is Atom = Tuple.is;
-    export const unit: (a: Atom) => number = Tuple.fst;
-    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;
-
-    export function createEmptyArray(n: number): Atom[] { return new Float64Array(n) as any; }
-
-    /** 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 updateLocation(structure: Structure, l: Location, atom: Atom) {
-        l.unit = structure.units[unit(atom)];
-        l.atom = index(atom);
-        return l;
-    }
-
-    export function property<T>(p: Property<T>) { return p; }
-}
-
-export default Atom

+ 0 - 71
src/mol-model/structure/structure/atom/group.ts

@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import { OrderedSet } from 'mol-data/int'
-import Unit from '../unit'
-
-interface AtomGroup {
-    atoms: OrderedSet,
-    id: number
-}
-
-namespace AtomGroup {
-    export const Empty = createNew(OrderedSet.Empty)
-
-    export function singleton(idx: number) {
-        return createNew(OrderedSet.ofSingleton(idx));
-    }
-
-    export function createNew(atoms: OrderedSet): AtomGroup {
-        return { id: nextId(), atoms };
-    }
-
-    export function create(unit: Unit, atoms: OrderedSet): AtomGroup {
-        if (OrderedSet.areEqual(atoms, unit.fullGroup.atoms)) return unit.fullGroup;
-        return createNew(atoms);
-    }
-
-    export function createChild(parent: AtomGroup, atoms: OrderedSet): AtomGroup {
-        if (OrderedSet.areEqual(atoms, parent.atoms)) return parent;
-        return createNew(atoms);
-    }
-
-    export function size(group: AtomGroup) { return OrderedSet.size(group.atoms); }
-    export function has(group: AtomGroup, atom: number) { return OrderedSet.has(group.atoms, atom); }
-    export function getAt(group: AtomGroup, i: number) { return OrderedSet.getAt(group.atoms, i); }
-    export function indexOf(group: AtomGroup, atom: number) { return OrderedSet.indexOf(group.atoms, atom); }
-    export function hashCode(group: AtomGroup) { return OrderedSet.hashCode(group.atoms); }
-    export function areEqual(a: AtomGroup, b: AtomGroup) { return OrderedSet.areEqual(a.atoms, b.atoms); }
-
-    export function intersect(a: AtomGroup, b: AtomGroup) {
-        const set = OrderedSet.intersect(a.atoms, b.atoms);
-        if (set === a.atoms) return a;
-        if (set === b.atoms) return b;
-        return createNew(set);
-    }
-
-    export function union(a: AtomGroup, b: AtomGroup) {
-        const set = OrderedSet.union(a.atoms, b.atoms);
-        if (set === a.atoms) return a;
-        if (set === b.atoms) return b;
-        return createNew(set);
-    }
-
-    export function subtract(a: AtomGroup, b: AtomGroup) {
-        const set = OrderedSet.subtract(a.atoms, b.atoms);
-        if (set === a.atoms) return a;
-        return createNew(set);
-    }
-
-    let _id = 0;
-    function nextId() {
-        const ret = _id;
-        _id = (_id + 1) % 0x3fffffff;
-        return ret;
-    }
-}
-
-export default AtomGroup

+ 0 - 60
src/mol-model/structure/structure/atom/set.ts

@@ -1,60 +0,0 @@
-/**
- * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import { SortedArray, Iterator, OrderedSet } from 'mol-data/int'
-import Atom from '../atom'
-import AtomGroup from './group'
-import * as Impl from './impl/set'
-import * as Builders from './impl/set-builder'
-
-/** A map-like representation of grouped atom set */
-namespace AtomSet {
-    export const Empty: AtomSet = Impl.Empty 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 unitIds: (set: AtomSet) => SortedArray = Impl.getKeys as any;
-    export const unitHas: (set: AtomSet, id: number) => boolean = Impl.hasKey as any;
-    export const unitGetId: (set: AtomSet, i: number) => number = Impl.getKey as any;
-
-    export const unitGetById: (set: AtomSet, key: number) => AtomGroup = Impl.getByKey as any;
-    export const unitGetByIndex: (set: AtomSet, i: number) => AtomGroup = Impl.getByIndex as any;
-
-    export const atomCount: (set: AtomSet) => number = Impl.size as any;
-    export const atomHas: (set: AtomSet, x: Atom) => boolean = Impl.hasAtom as any;
-    export const atomIndexOf: (set: AtomSet, x: Atom) => number = Impl.indexOf as any;
-    export const atomGetAt: (set: AtomSet, i: number) => Atom = Impl.getAt as any;
-    export const atoms: (set: AtomSet) => Iterator<Atom> = Impl.values as any;
-
-    export const hashCode: (set: AtomSet) => number = Impl.hashCode as any;
-    export const areEqual: (a: AtomSet, b: AtomSet) => boolean = Impl.areEqual as any;
-    export const areIntersecting: (a: AtomSet, b: AtomSet) => boolean = Impl.areIntersecting as any;
-
-    export const union: (sets: ArrayLike<AtomSet>, template: AtomSet) => AtomSet = Impl.unionMany as any;
-    export const intersect: (a: AtomSet, b: AtomSet) => AtomSet = Impl.intersect as any;
-    export const subtract: (a: AtomSet, b: AtomSet) => AtomSet = Impl.subtract as any;
-
-    export type Builder = Builders.Builder
-    export const LinearBuilder = Builders.LinearBuilder
-    export const UnsortedBuilder = Builders.UnsortedBuilder
-
-    export interface Generator { add(unit: number, set: AtomGroup): void, getSet(): AtomSet }
-    export const Generator: () => Generator = Impl.Generator as any
-
-    export interface TemplateGenerator { add(unit: number, set: OrderedSet): void, getSet(): AtomSet }
-    export const TemplateGenerator: (template: AtomSet) => TemplateGenerator = Impl.TemplateGenerator as any
-
-    // TODO: bounding sphere
-    // TODO: distance, areWithIn?
-    // TODO: check connected
-    // TODO: add "parent" property? how to avoid using too much memory? Transitive parents? Parent unlinking?
-}
-
-interface AtomSet { '@type': 'atom-set' | Atom['@type'] }
-
-export default AtomSet

+ 40 - 0
src/mol-model/structure/structure/element.ts

@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Tuple } from 'mol-data/int'
+import Unit from './unit'
+import Structure from './structure'
+
+/** Atom pointer */
+interface Element { '@type': Tuple['@type'] }
+
+namespace Element {
+    export const Zero: Element = Tuple.Zero;
+    export const create: (unit: number, index: number) => Element = Tuple.create;
+    export const is: (x: any) => x is Element = Tuple.is;
+    export const unit: (e: Element) => number = Tuple.fst;
+    export const index: (e: Element) => number = Tuple.snd;
+    export const areEqual: (e: Element, b: Element) => boolean = Tuple.areEqual;
+    export const hashCode: (e: Element) => number = Tuple.hashCode;
+
+    export function createEmptyArray(n: number): Element[] { return new Float64Array(n) as any; }
+
+    /** All the information required to access element properties */
+    export interface Location { unit: Unit, element: number }
+    export function Location(): Location { return { unit: {} as any, element: 0 }; }
+    export interface Property<T> { (location: Location): T }
+    export interface Predicate extends Property<boolean> { }
+
+    export function updateLocation(structure: Structure, l: Location, element: Element) {
+        l.unit = structure.units[unit(element)];
+        l.element = index(element);
+        return l;
+    }
+
+    export function property<T>(p: Property<T>) { return p; }
+}
+
+export default Element

+ 71 - 0
src/mol-model/structure/structure/element/group.ts

@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { OrderedSet } from 'mol-data/int'
+import Unit from '../unit'
+
+interface ElementGroup {
+    elements: OrderedSet,
+    id: number
+}
+
+namespace ElementGroup {
+    export const Empty = createNew(OrderedSet.Empty)
+
+    export function singleton(idx: number) {
+        return createNew(OrderedSet.ofSingleton(idx));
+    }
+
+    export function createNew(elements: OrderedSet): ElementGroup {
+        return { id: nextId(), elements };
+    }
+
+    export function create(unit: Unit, elements: OrderedSet): ElementGroup {
+        if (OrderedSet.areEqual(elements, unit.fullGroup.elements)) return unit.fullGroup;
+        return createNew(elements);
+    }
+
+    export function createChild(parent: ElementGroup, elements: OrderedSet): ElementGroup {
+        if (OrderedSet.areEqual(elements, parent.elements)) return parent;
+        return createNew(elements);
+    }
+
+    export function size(group: ElementGroup) { return OrderedSet.size(group.elements); }
+    export function has(group: ElementGroup, element: number) { return OrderedSet.has(group.elements, element); }
+    export function getAt(group: ElementGroup, i: number) { return OrderedSet.getAt(group.elements, i); }
+    export function indexOf(group: ElementGroup, element: number) { return OrderedSet.indexOf(group.elements, element); }
+    export function hashCode(group: ElementGroup) { return OrderedSet.hashCode(group.elements); }
+    export function areEqual(a: ElementGroup, b: ElementGroup) { return OrderedSet.areEqual(a.elements, b.elements); }
+
+    export function intersect(a: ElementGroup, b: ElementGroup) {
+        const set = OrderedSet.intersect(a.elements, b.elements);
+        if (set === a.elements) return a;
+        if (set === b.elements) return b;
+        return createNew(set);
+    }
+
+    export function union(a: ElementGroup, b: ElementGroup) {
+        const set = OrderedSet.union(a.elements, b.elements);
+        if (set === a.elements) return a;
+        if (set === b.elements) return b;
+        return createNew(set);
+    }
+
+    export function subtract(a: ElementGroup, b: ElementGroup) {
+        const set = OrderedSet.subtract(a.elements, b.elements);
+        if (set === a.elements) return a;
+        return createNew(set);
+    }
+
+    let _id = 0;
+    function nextId() {
+        const ret = _id;
+        _id = (_id + 1) % 0x3fffffff;
+        return ret;
+    }
+}
+
+export default ElementGroup

+ 0 - 0
src/mol-model/structure/structure/atom/impl/properties.ts → src/mol-model/structure/structure/element/impl/properties.ts


+ 15 - 15
src/mol-model/structure/structure/atom/impl/set-builder.ts → src/mol-model/structure/structure/element/impl/set-builder.ts

@@ -4,8 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author David Sehnal <david.sehnal@gmail.com>
  */
  */
 
 
-import AtomSet from '../set'
-import Atom from '../../atom'
+import ElementSet from '../set'
+import Element from '../../element'
 import { OrderedSet, IntMap } from 'mol-data/int'
 import { OrderedSet, IntMap } from 'mol-data/int'
 import { sortArray } from 'mol-data/util/sort'
 import { sortArray } from 'mol-data/util/sort'
 
 
@@ -14,28 +14,28 @@ export class Builder {
     private units = IntMap.Mutable<number[]>();
     private units = IntMap.Mutable<number[]>();
     private currentUnit: number[] = [];
     private currentUnit: number[] = [];
 
 
-    atomCount = 0;
+    elementCount = 0;
 
 
-    add(u: number, a: number) {
+    add(u: number, e: number) {
         const unit = this.units.get(u);
         const unit = this.units.get(u);
-        if (!!unit) { unit[unit.length] = a; }
+        if (!!unit) { unit[unit.length] = e; }
         else {
         else {
-            this.units.set(u, [a]);
+            this.units.set(u, [e]);
             this.keys[this.keys.length] = u;
             this.keys[this.keys.length] = u;
         }
         }
-        this.atomCount++;
+        this.elementCount++;
     }
     }
 
 
     beginUnit() { this.currentUnit = this.currentUnit.length > 0 ? [] : this.currentUnit; }
     beginUnit() { this.currentUnit = this.currentUnit.length > 0 ? [] : this.currentUnit; }
-    addToUnit(a: number) { this.currentUnit[this.currentUnit.length] = a; this.atomCount++; }
+    addToUnit(a: number) { this.currentUnit[this.currentUnit.length] = a; this.elementCount++; }
     commitUnit(u: number) {
     commitUnit(u: number) {
         if (this.currentUnit.length === 0) return;
         if (this.currentUnit.length === 0) return;
         this.keys[this.keys.length] = u;
         this.keys[this.keys.length] = u;
         this.units.set(u, this.currentUnit);
         this.units.set(u, this.currentUnit);
     }
     }
 
 
-    getSet(): AtomSet {
-        const generator = AtomSet.TemplateGenerator(this.parent);
+    getSet(): ElementSet {
+        const generator = ElementSet.TemplateGenerator(this.parent);
 
 
         for (let i = 0, _i = this.keys.length; i < _i; i++) {
         for (let i = 0, _i = this.keys.length; i < _i; i++) {
             const k = this.keys[i];
             const k = this.keys[i];
@@ -48,18 +48,18 @@ export class Builder {
         return generator.getSet();
         return generator.getSet();
     }
     }
 
 
-    singleton(): Atom {
+    singleton(): Element {
         const u = this.keys[0];
         const u = this.keys[0];
-        return Atom.create(u, this.units.get(u)[0]);
+        return Element.create(u, this.units.get(u)[0]);
     }
     }
 
 
-    constructor(private parent: AtomSet, private sorted: boolean) { }
+    constructor(private parent: ElementSet, private sorted: boolean) { }
 }
 }
 
 
-export function LinearBuilder(parent: AtomSet) {
+export function LinearBuilder(parent: ElementSet) {
     return new Builder(parent, true);
     return new Builder(parent, true);
 }
 }
 
 
-export function UnsortedBuilder(parent: AtomSet) {
+export function UnsortedBuilder(parent: ElementSet) {
     return new Builder(parent, false);
     return new Builder(parent, false);
 }
 }

+ 80 - 80
src/mol-model/structure/structure/atom/impl/set.ts → src/mol-model/structure/structure/element/impl/set.ts

@@ -7,83 +7,83 @@
 import { SortedArray, Interval, Iterator, OrderedSet as OS, IntMap } from 'mol-data/int'
 import { SortedArray, Interval, Iterator, OrderedSet as OS, IntMap } from 'mol-data/int'
 import { sortArray } from 'mol-data/util/sort'
 import { sortArray } from 'mol-data/util/sort'
 import { hash1 } from 'mol-data/util/hash-functions'
 import { hash1 } from 'mol-data/util/hash-functions'
-import Atom from '../../atom'
-import AtomGroup from '../group'
+import Element from '../../element'
+import ElementGroup from '../group'
 
 
 /** Long and painful implementation starts here */
 /** Long and painful implementation starts here */
 
 
-export type AtomSetImpl = { groups: IntMap<AtomGroup>, offsets: Int32Array, hashCode: number, keys: SortedArray }
+export type ElementSetImpl = { groups: IntMap<ElementGroup>, offsets: Int32Array, hashCode: number, keys: SortedArray }
 
 
-export const Empty: AtomSetImpl = { groups: IntMap.Empty, offsets: new Int32Array(1), hashCode: 0, keys: SortedArray.Empty };
+export const Empty: ElementSetImpl = { groups: IntMap.Empty, offsets: new Int32Array(1), hashCode: 0, keys: SortedArray.Empty };
 
 
-export function ofAtoms(atoms: ArrayLike<Atom>, template: AtomSetImpl): AtomSetImpl {
-    return ofAtomsImpl(atoms, template);
+export function ofElements(elements: ArrayLike<Element>, template: ElementSetImpl): ElementSetImpl {
+    return ofElementsImpl(elements, template);
 }
 }
 
 
-export function singleton(atom: Atom, template: AtomSetImpl) {
-    return singletonImpl(atom, template);
+export function singleton(element: Element, template: ElementSetImpl) {
+    return singletonImpl(element, template);
 }
 }
 
 
-export function getKeys(set: AtomSetImpl): SortedArray {
+export function getKeys(set: ElementSetImpl): SortedArray {
     return set.keys;
     return set.keys;
 }
 }
 
 
-export function keyCount(set: AtomSetImpl): number {
+export function keyCount(set: ElementSetImpl): number {
     return set.keys.length;
     return set.keys.length;
 }
 }
 
 
-export function hasKey(set: AtomSetImpl, key: number): boolean {
+export function hasKey(set: ElementSetImpl, key: number): boolean {
     return set.groups.has(key);
     return set.groups.has(key);
 }
 }
 
 
-export function getKey(set: AtomSetImpl, index: number): number {
+export function getKey(set: ElementSetImpl, index: number): number {
     return set.keys[index];
     return set.keys[index];
 }
 }
 
 
-export function hasAtom(set: AtomSetImpl, t: Atom): boolean {
-    const os = set.groups.get(Atom.unit(t));
-    return !!os && AtomGroup.has(os, Atom.index(t));
+export function hasAtom(set: ElementSetImpl, t: Element): boolean {
+    const os = set.groups.get(Element.unit(t));
+    return !!os && ElementGroup.has(os, Element.index(t));
 }
 }
 
 
-export function getByKey(set: AtomSetImpl, key: number): AtomGroup {
-    return set.groups.get(key) || AtomGroup.Empty;
+export function getByKey(set: ElementSetImpl, key: number): ElementGroup {
+    return set.groups.get(key) || ElementGroup.Empty;
 }
 }
 
 
-export function getByIndex(set: AtomSetImpl, index: number): AtomGroup {
+export function getByIndex(set: ElementSetImpl, index: number): ElementGroup {
     const key = set.keys[index];
     const key = set.keys[index];
-    return set.groups.get(key) || AtomGroup.Empty;
+    return set.groups.get(key) || ElementGroup.Empty;
 }
 }
 
 
-export function getAt(set: AtomSetImpl, i: number): Atom {
+export function getAt(set: ElementSetImpl, i: number): Element {
     const { offsets, keys } = set;
     const { offsets, keys } = set;
     const o = getOffsetIndex(offsets, i);
     const o = getOffsetIndex(offsets, i);
-    if (o >= offsets.length - 1) return Atom.Zero;
+    if (o >= offsets.length - 1) return Element.Zero;
     const k = keys[o];
     const k = keys[o];
-    const e = AtomGroup.getAt(set.groups.get(k), i - offsets[o]);
-    return Atom.create(k, e);
+    const e = ElementGroup.getAt(set.groups.get(k), i - offsets[o]);
+    return Element.create(k, e);
 }
 }
 
 
-export function indexOf(set: AtomSetImpl, t: Atom) {
+export function indexOf(set: ElementSetImpl, t: Element) {
     const { keys } = set;
     const { keys } = set;
-    const u = Atom.unit(t);
+    const u = Element.unit(t);
     const setIdx = SortedArray.indexOf(keys, u);
     const setIdx = SortedArray.indexOf(keys, u);
     if (setIdx < 0) return -1;
     if (setIdx < 0) return -1;
-    const o = AtomGroup.indexOf(set.groups.get(u), Atom.index(t));
+    const o = ElementGroup.indexOf(set.groups.get(u), Element.index(t));
     if (o < 0) return -1;
     if (o < 0) return -1;
     return set.offsets[setIdx] + o;
     return set.offsets[setIdx] + o;
 }
 }
 
 
 /** Number elements in the "child" sets */
 /** Number elements in the "child" sets */
-export function size(set: AtomSetImpl) {
+export function size(set: ElementSetImpl) {
     return set.offsets[set.offsets.length - 1];
     return set.offsets[set.offsets.length - 1];
 }
 }
 
 
-export function hashCode(set: AtomSetImpl) {
+export function hashCode(set: ElementSetImpl) {
     if (set.hashCode !== -1) return set.hashCode;
     if (set.hashCode !== -1) return set.hashCode;
     return computeHash(set);
     return computeHash(set);
 }
 }
 
 
-export function areEqual(a: AtomSetImpl, b: AtomSetImpl) {
+export function areEqual(a: ElementSetImpl, b: ElementSetImpl) {
     if (a === b) return true;
     if (a === b) return true;
     if (size(a) !== size(a)) return false;
     if (size(a) !== size(a)) return false;
 
 
@@ -93,12 +93,12 @@ export function areEqual(a: AtomSetImpl, b: AtomSetImpl) {
     const { groups: bG } = b;
     const { groups: bG } = b;
     for (let i = 0, _i = keys.length; i < _i; i++) {
     for (let i = 0, _i = keys.length; i < _i; i++) {
         const k = keys[i];
         const k = keys[i];
-        if (!AtomGroup.areEqual(aG.get(k), bG.get(k))) return false;
+        if (!ElementGroup.areEqual(aG.get(k), bG.get(k))) return false;
     }
     }
     return true;
     return true;
 }
 }
 
 
-export function areIntersecting(a: AtomSetImpl, b: AtomSetImpl) {
+export function areIntersecting(a: ElementSetImpl, b: ElementSetImpl) {
     if (a === b) return true;
     if (a === b) return true;
     const keysA = a.keys, keysB = b.keys;
     const keysA = a.keys, keysB = b.keys;
     if (!SortedArray.areIntersecting(a.keys, b.keys)) return false;
     if (!SortedArray.areIntersecting(a.keys, b.keys)) return false;
@@ -109,12 +109,12 @@ export function areIntersecting(a: AtomSetImpl, b: AtomSetImpl) {
     for (let i = start; i < end; i++) {
     for (let i = start; i < end; i++) {
         const k = keysA[i];
         const k = keysA[i];
         const ak = aG.get(k), bk = bG.get(k);
         const ak = aG.get(k), bk = bG.get(k);
-        if (!!ak && !!bk && OS.areIntersecting(ak.atoms, bk.atoms)) return true;
+        if (!!ak && !!bk && OS.areIntersecting(ak.elements, bk.elements)) return true;
     }
     }
     return false;
     return false;
 }
 }
 
 
-export function intersect(a: AtomSetImpl, b: AtomSetImpl) {
+export function intersect(a: ElementSetImpl, b: ElementSetImpl) {
     if (a === b) return a;
     if (a === b) return a;
 
 
     const keysA = a.keys, keysB = b.keys;
     const keysA = a.keys, keysB = b.keys;
@@ -130,12 +130,12 @@ export function intersect(a: AtomSetImpl, b: AtomSetImpl) {
         const bk = bG.get(k);
         const bk = bG.get(k);
         if (!bk) continue;
         if (!bk) continue;
         const ak = aG.get(k);
         const ak = aG.get(k);
-        generator.add(k, AtomGroup.intersect(aG.get(k), bk), ak, bk);
+        generator.add(k, ElementGroup.intersect(aG.get(k), bk), ak, bk);
     }
     }
     return generator.getSet();
     return generator.getSet();
 }
 }
 
 
-export function subtract(a: AtomSetImpl, b: AtomSetImpl) {
+export function subtract(a: ElementSetImpl, b: ElementSetImpl) {
     if (a === b) return Empty;
     if (a === b) return Empty;
 
 
     const keysA = a.keys, keysB = b.keys;
     const keysA = a.keys, keysB = b.keys;
@@ -155,7 +155,7 @@ export function subtract(a: AtomSetImpl, b: AtomSetImpl) {
         const k = keysA[i];
         const k = keysA[i];
         const ak = aG.get(k), bk = bG.get(k);
         const ak = aG.get(k), bk = bG.get(k);
         if (!!bk) {
         if (!!bk) {
-            const subtraction = AtomGroup.subtract(ak, bk);
+            const subtraction = ElementGroup.subtract(ak, bk);
             generator.addA(k, subtraction, ak);
             generator.addA(k, subtraction, ak);
         } else {
         } else {
             generator.addA(k, ak, ak);
             generator.addA(k, ak, ak);
@@ -169,11 +169,11 @@ export function subtract(a: AtomSetImpl, b: AtomSetImpl) {
     return generator.getSet();
     return generator.getSet();
 }
 }
 
 
-export function unionMany(sets: ArrayLike<AtomSetImpl>, template: AtomSetImpl) {
+export function unionMany(sets: ArrayLike<ElementSetImpl>, template: ElementSetImpl) {
     return findUnion(sets, template);
     return findUnion(sets, template);
 }
 }
 
 
-class ElementsIterator implements Iterator<Atom> {
+class ElementsIterator implements Iterator<Element> {
     private unit: number = 0;
     private unit: number = 0;
     private keyCount: number;
     private keyCount: number;
     private setIndex = -1;
     private setIndex = -1;
@@ -184,8 +184,8 @@ class ElementsIterator implements Iterator<Atom> {
     hasNext: boolean = false;
     hasNext: boolean = false;
 
 
     move() {
     move() {
-        if (!this.hasNext) return Atom.Zero;
-        const ret = Atom.create(this.unit, OS.getAt(this.currentSet, this.currentIndex++));
+        if (!this.hasNext) return Element.Zero;
+        const ret = Element.create(this.unit, OS.getAt(this.currentSet, this.currentIndex++));
         if (this.currentIndex >= this.currentSize) this.advance();
         if (this.currentIndex >= this.currentSize) this.advance();
         return ret;
         return ret;
     }
     }
@@ -196,27 +196,27 @@ class ElementsIterator implements Iterator<Atom> {
             return false;
             return false;
         }
         }
         this.unit = this.elements.keys[this.setIndex];
         this.unit = this.elements.keys[this.setIndex];
-        this.currentSet = this.elements.groups.get(this.unit).atoms;
+        this.currentSet = this.elements.groups.get(this.unit).elements;
         this.currentIndex = 0;
         this.currentIndex = 0;
         this.currentSize = OS.size(this.currentSet);
         this.currentSize = OS.size(this.currentSet);
         return true;
         return true;
     }
     }
 
 
-    constructor(private elements: AtomSetImpl) {
+    constructor(private elements: ElementSetImpl) {
         this.keyCount = elements.keys.length;
         this.keyCount = elements.keys.length;
         this.hasNext = this.keyCount > 0;
         this.hasNext = this.keyCount > 0;
         this.advance();
         this.advance();
     }
     }
 }
 }
 
 
-export function values(set: AtomSetImpl): Iterator<Atom> {
+export function values(set: ElementSetImpl): Iterator<Element> {
     return new ElementsIterator(set);
     return new ElementsIterator(set);
 }
 }
 
 
 export class TemplateAtomSetGenerator {
 export class TemplateAtomSetGenerator {
     private keys: number[] = [];
     private keys: number[] = [];
-    private groups = IntMap.Mutable<AtomGroup>();
-    private templateGroups: IntMap<AtomGroup>;
+    private groups = IntMap.Mutable<ElementGroup>();
+    private templateGroups: IntMap<ElementGroup>;
     private equalGroups = 0;
     private equalGroups = 0;
 
 
     add(unit: number, set: OS) {
     add(unit: number, set: OS) {
@@ -224,44 +224,44 @@ export class TemplateAtomSetGenerator {
         this.keys[this.keys.length] = unit;
         this.keys[this.keys.length] = unit;
         if (this.templateGroups.has(unit)) {
         if (this.templateGroups.has(unit)) {
             const t = this.templateGroups.get(unit);
             const t = this.templateGroups.get(unit);
-            if (OS.areEqual(t.atoms, set)) {
+            if (OS.areEqual(t.elements, set)) {
                 this.groups.set(unit, t);
                 this.groups.set(unit, t);
                 this.equalGroups++;
                 this.equalGroups++;
             } else {
             } else {
-                this.groups.set(unit, AtomGroup.createNew(set));
+                this.groups.set(unit, ElementGroup.createNew(set));
             }
             }
         } else {
         } else {
-            this.groups.set(unit, AtomGroup.createNew(set));
+            this.groups.set(unit, ElementGroup.createNew(set));
         }
         }
     }
     }
 
 
-    getSet(): AtomSetImpl {
+    getSet(): ElementSetImpl {
         if (this.equalGroups === this.template.keys.length && this.equalGroups === this.keys.length) {
         if (this.equalGroups === this.template.keys.length && this.equalGroups === this.keys.length) {
             return this.template;
             return this.template;
         }
         }
         return create(this.keys, this.groups);
         return create(this.keys, this.groups);
     }
     }
 
 
-    constructor(private template: AtomSetImpl) {
+    constructor(private template: ElementSetImpl) {
         this.templateGroups = template.groups;
         this.templateGroups = template.groups;
     }
     }
 }
 }
 
 
-export function TemplateGenerator(template: AtomSetImpl) {
+export function TemplateGenerator(template: ElementSetImpl) {
     return new TemplateAtomSetGenerator(template);
     return new TemplateAtomSetGenerator(template);
 }
 }
 
 
 export class AtomSetGenerator {
 export class AtomSetGenerator {
     private keys: number[] = [];
     private keys: number[] = [];
-    private groups = IntMap.Mutable<AtomGroup>();
+    private groups = IntMap.Mutable<ElementGroup>();
 
 
-    add(unit: number, group: AtomGroup) {
-        if (AtomGroup.size(group) === 0) return;
+    add(unit: number, group: ElementGroup) {
+        if (ElementGroup.size(group) === 0) return;
         this.keys[this.keys.length] = unit;
         this.keys[this.keys.length] = unit;
         this.groups.set(unit, group);
         this.groups.set(unit, group);
     }
     }
 
 
-    getSet(): AtomSetImpl {
+    getSet(): ElementSetImpl {
         return create(this.keys, this.groups);
         return create(this.keys, this.groups);
     }
     }
 }
 }
@@ -273,42 +273,42 @@ export function Generator() {
 /** When adding groups, compare them to existing ones. If they all match, return the whole original set. */
 /** When adding groups, compare them to existing ones. If they all match, return the whole original set. */
 class ChildGenerator {
 class ChildGenerator {
     private keys: number[] = [];
     private keys: number[] = [];
-    private groups = IntMap.Mutable<AtomGroup>();
+    private groups = IntMap.Mutable<ElementGroup>();
     private aEqual = 0;
     private aEqual = 0;
     private bEqual = 0;
     private bEqual = 0;
 
 
-    add(unit: number, group: AtomGroup, a: AtomGroup, b: AtomGroup) {
-        if (AtomGroup.size(group) === 0) return;
+    add(unit: number, group: ElementGroup, a: ElementGroup, b: ElementGroup) {
+        if (ElementGroup.size(group) === 0) return;
         if (a === group) this.aEqual++;
         if (a === group) this.aEqual++;
         if (b === group) this.bEqual++;
         if (b === group) this.bEqual++;
         this.keys[this.keys.length] = unit;
         this.keys[this.keys.length] = unit;
         this.groups.set(unit, group);
         this.groups.set(unit, group);
     }
     }
 
 
-    addA(unit: number, group: AtomGroup, a: AtomGroup) {
-        if (AtomGroup.size(group) === 0) return;
+    addA(unit: number, group: ElementGroup, a: ElementGroup) {
+        if (ElementGroup.size(group) === 0) return;
 
 
         if (a === group) this.aEqual++;
         if (a === group) this.aEqual++;
         this.keys[this.keys.length] = unit;
         this.keys[this.keys.length] = unit;
         this.groups.set(unit, group);
         this.groups.set(unit, group);
     }
     }
 
 
-    constructor(private a: AtomSetImpl, private b: AtomSetImpl) {
+    constructor(private a: ElementSetImpl, private b: ElementSetImpl) {
     }
     }
 
 
-    getSet(): AtomSetImpl {
+    getSet(): ElementSetImpl {
         if (this.aEqual === this.a.keys.length) return this.a;
         if (this.aEqual === this.a.keys.length) return this.a;
         if (this.bEqual === this.b.keys.length) return this.b;
         if (this.bEqual === this.b.keys.length) return this.b;
         return create(this.keys, this.groups);
         return create(this.keys, this.groups);
     }
     }
 }
 }
 
 
-function create(keys: number[], groups: IntMap<AtomGroup>): AtomSetImpl {
+function create(keys: number[], groups: IntMap<ElementGroup>): ElementSetImpl {
     sortArray(keys);
     sortArray(keys);
     let runningSize = 0;
     let runningSize = 0;
     const offsets = new Int32Array(keys.length + 1);
     const offsets = new Int32Array(keys.length + 1);
     for (let i = 0, _i = keys.length; i < _i; i++) {
     for (let i = 0, _i = keys.length; i < _i; i++) {
-        runningSize += AtomGroup.size(groups.get(keys[i]));
+        runningSize += ElementGroup.size(groups.get(keys[i]));
         offsets[i + 1] = runningSize;
         offsets[i + 1] = runningSize;
     }
     }
     return { keys: SortedArray.ofSortedArray(keys), groups: IntMap.asImmutable(groups), offsets, hashCode: -1 };
     return { keys: SortedArray.ofSortedArray(keys), groups: IntMap.asImmutable(groups), offsets, hashCode: -1 };
@@ -336,14 +336,14 @@ function normalizeArray(xs: number[]): number[] {
     return xs;
     return xs;
 }
 }
 
 
-function ofAtomsImpl(xs: ArrayLike<Atom>, template: AtomSetImpl) {
+function ofElementsImpl(xs: ArrayLike<Element>, template: ElementSetImpl) {
     if (xs.length === 0) return Empty;
     if (xs.length === 0) return Empty;
 
 
     const elements = IntMap.Mutable<number[]>();
     const elements = IntMap.Mutable<number[]>();
     const keys: number[] = [];
     const keys: number[] = [];
     for (let i = 0, _i = xs.length; i < _i; i++) {
     for (let i = 0, _i = xs.length; i < _i; i++) {
         const x = xs[i];
         const x = xs[i];
-        const u = Atom.unit(x), v = Atom.index(x);
+        const u = Element.unit(x), v = Element.index(x);
         if (elements.has(u)) {
         if (elements.has(u)) {
             const set = elements.get(u);
             const set = elements.get(u);
             set[set.length] = v;
             set[set.length] = v;
@@ -362,18 +362,18 @@ 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);
+function singletonImpl(element: Element, template: ElementSetImpl) {
+    const k = Element.unit(element), i = Element.index(element);
     const { groups } = template;
     const { groups } = template;
-    const gs = IntMap.Mutable<AtomGroup>();
+    const gs = IntMap.Mutable<ElementGroup>();
     if (groups.has(k)) {
     if (groups.has(k)) {
         const g = groups.get(k);
         const g = groups.get(k);
-        if (AtomGroup.size(g) === 1 && AtomGroup.getAt(g, 0) === i) {
+        if (ElementGroup.size(g) === 1 && ElementGroup.getAt(g, 0) === i) {
             gs.set(k, g);
             gs.set(k, g);
             return create([k], gs);
             return create([k], gs);
         }
         }
     }
     }
-    gs.set(k, AtomGroup.createNew(OS.ofSingleton(i)));
+    gs.set(k, ElementGroup.createNew(OS.ofSingleton(i)));
     return create([k], gs);
     return create([k], gs);
 }
 }
 
 
@@ -392,13 +392,13 @@ function getOffsetIndex(xs: ArrayLike<number>, value: number) {
     return value < xs[min] ? min - 1 : min;
     return value < xs[min] ? min - 1 : min;
 }
 }
 
 
-function computeHash(set: AtomSetImpl) {
+function computeHash(set: ElementSetImpl) {
     const { keys, groups } = set;
     const { keys, groups } = set;
     let hash = 23;
     let hash = 23;
     for (let i = 0, _i = keys.length; i < _i; i++) {
     for (let i = 0, _i = keys.length; i < _i; i++) {
         const k = keys[i];
         const k = keys[i];
         hash = (31 * hash + k) | 0;
         hash = (31 * hash + k) | 0;
-        hash = (31 * hash + AtomGroup.hashCode(groups.get(k))) | 0;
+        hash = (31 * hash + ElementGroup.hashCode(groups.get(k))) | 0;
     }
     }
     hash = (31 * hash + size(set)) | 0;
     hash = (31 * hash + size(set)) | 0;
     hash = hash1(hash);
     hash = hash1(hash);
@@ -406,13 +406,13 @@ function computeHash(set: AtomSetImpl) {
     return hash;
     return hash;
 }
 }
 
 
-function findUnion(sets: ArrayLike<AtomSetImpl>, template: AtomSetImpl) {
+function findUnion(sets: ArrayLike<ElementSetImpl>, template: ElementSetImpl) {
     if (!sets.length) return Empty;
     if (!sets.length) return Empty;
     if (sets.length === 1) return sets[0];
     if (sets.length === 1) return sets[0];
     if (sets.length === 2 && sets[0] === sets[1]) return sets[0];
     if (sets.length === 2 && sets[0] === sets[1]) return sets[0];
 
 
     const keys: number[] = [];
     const keys: number[] = [];
-    const groups = IntMap.Mutable<AtomGroup>();
+    const groups = IntMap.Mutable<ElementGroup>();
     for (let i = 0, _i = sets.length; i < _i; i++) {
     for (let i = 0, _i = sets.length; i < _i; i++) {
         unionInto(keys, groups, sets[i]);
         unionInto(keys, groups, sets[i]);
     }
     }
@@ -420,12 +420,12 @@ function findUnion(sets: ArrayLike<AtomSetImpl>, template: AtomSetImpl) {
     return normalizeUnion(keys, groups, template);
     return normalizeUnion(keys, groups, template);
 }
 }
 
 
-function normalizeUnion(keys: number[], groups: IntMap.Mutable<AtomGroup>, template: AtomSetImpl) {
+function normalizeUnion(keys: number[], groups: IntMap.Mutable<ElementGroup>, template: ElementSetImpl) {
     let equalCount = 0;
     let equalCount = 0;
-    let tg = template.groups, a: AtomGroup, t: AtomGroup;
+    let tg = template.groups, a: ElementGroup, t: ElementGroup;
     for (let i = 0, _i = keys.length; i < _i; i++) {
     for (let i = 0, _i = keys.length; i < _i; i++) {
         const k = keys[i];
         const k = keys[i];
-        if (tg.has(k) && AtomGroup.areEqual(a = groups.get(k), t = tg.get(k))) {
+        if (tg.has(k) && ElementGroup.areEqual(a = groups.get(k), t = tg.get(k))) {
             groups.set(k, t);
             groups.set(k, t);
             equalCount++;
             equalCount++;
         }
         }
@@ -433,13 +433,13 @@ function normalizeUnion(keys: number[], groups: IntMap.Mutable<AtomGroup>, templ
     return equalCount === template.keys.length && equalCount === keys.length ? template : create(keys, groups);
     return equalCount === template.keys.length && equalCount === keys.length ? template : create(keys, groups);
 }
 }
 
 
-function unionInto(keys: number[], groups: IntMap.Mutable<AtomGroup>, a: AtomSetImpl) {
+function unionInto(keys: number[], groups: IntMap.Mutable<ElementGroup>, a: ElementSetImpl) {
     const setKeys = a.keys;
     const setKeys = a.keys;
     const { groups: aG } = a;
     const { groups: aG } = a;
     for (let i = 0, _i = setKeys.length; i < _i; i++) {
     for (let i = 0, _i = setKeys.length; i < _i; i++) {
         const k = setKeys[i];
         const k = setKeys[i];
         if (groups.has(k)) {
         if (groups.has(k)) {
-            groups.set(k, AtomGroup.union(aG.get(k), groups.get(k)))
+            groups.set(k, ElementGroup.union(aG.get(k), groups.get(k)))
         } else {
         } else {
             keys[keys.length] = k;
             keys[keys.length] = k;
             groups.set(k, aG.get(k));
             groups.set(k, aG.get(k));

+ 60 - 0
src/mol-model/structure/structure/element/set.ts

@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { SortedArray, Iterator, OrderedSet } from 'mol-data/int'
+import Element from '../element'
+import ElementGroup from './group'
+import * as Impl from './impl/set'
+import * as Builders from './impl/set-builder'
+
+/** A map-like representation of grouped atom set */
+namespace ElementSet {
+    export const Empty: ElementSet = Impl.Empty as any;
+
+    export const ofAtoms: (elements: ArrayLike<Element>, template: ElementSet) => ElementSet = Impl.ofElements as any;
+    export const singleton: (element: Element, template: ElementSet) => ElementSet = Impl.singleton as any;
+
+    export const unitCount: (set: ElementSet) => number = Impl.keyCount as any;
+    export const unitIds: (set: ElementSet) => SortedArray = Impl.getKeys as any;
+    export const unitHas: (set: ElementSet, id: number) => boolean = Impl.hasKey as any;
+    export const unitGetId: (set: ElementSet, i: number) => number = Impl.getKey as any;
+
+    export const unitGetById: (set: ElementSet, key: number) => ElementGroup = Impl.getByKey as any;
+    export const unitGetByIndex: (set: ElementSet, i: number) => ElementGroup = Impl.getByIndex as any;
+
+    export const elementCount: (set: ElementSet) => number = Impl.size as any;
+    export const elementHas: (set: ElementSet, x: Element) => boolean = Impl.hasAtom as any;
+    export const elementIndexOf: (set: ElementSet, x: Element) => number = Impl.indexOf as any;
+    export const elementGetAt: (set: ElementSet, i: number) => Element = Impl.getAt as any;
+    export const elements: (set: ElementSet) => Iterator<Element> = Impl.values as any;
+
+    export const hashCode: (set: ElementSet) => number = Impl.hashCode as any;
+    export const areEqual: (a: ElementSet, b: ElementSet) => boolean = Impl.areEqual as any;
+    export const areIntersecting: (a: ElementSet, b: ElementSet) => boolean = Impl.areIntersecting as any;
+
+    export const union: (sets: ArrayLike<ElementSet>, template: ElementSet) => ElementSet = Impl.unionMany as any;
+    export const intersect: (a: ElementSet, b: ElementSet) => ElementSet = Impl.intersect as any;
+    export const subtract: (a: ElementSet, b: ElementSet) => ElementSet = Impl.subtract as any;
+
+    export type Builder = Builders.Builder
+    export const LinearBuilder = Builders.LinearBuilder
+    export const UnsortedBuilder = Builders.UnsortedBuilder
+
+    export interface Generator { add(unit: number, set: ElementGroup): void, getSet(): ElementSet }
+    export const Generator: () => Generator = Impl.Generator as any
+
+    export interface TemplateGenerator { add(unit: number, set: OrderedSet): void, getSet(): ElementSet }
+    export const TemplateGenerator: (template: ElementSet) => TemplateGenerator = Impl.TemplateGenerator as any
+
+    // TODO: bounding sphere
+    // TODO: distance, areWithIn?
+    // TODO: check connected
+    // TODO: add "parent" property? how to avoid using too much memory? Transitive parents? Parent unlinking?
+}
+
+interface ElementSet { '@type': 'element-set' | Element['@type'] }
+
+export default ElementSet

+ 24 - 24
src/mol-model/structure/structure/structure.ts

@@ -9,20 +9,20 @@ import { UniqueArray } from 'mol-data/generic'
 import SymmetryOperator from 'mol-math/geometry/symmetry-operator'
 import SymmetryOperator from 'mol-math/geometry/symmetry-operator'
 import { Model, Format } from '../model'
 import { Model, Format } from '../model'
 import Unit from './unit'
 import Unit from './unit'
-import AtomSet from './atom/set'
-import AtomGroup from './atom/group'
-import Atom from './atom'
+import ElementSet from './element/set'
+import ElementGroup from './element/group'
+import Element from './element'
 
 
-// A structure is a pair of "units" and an atom set.
-// Each unit contains the data and transformation of its corresponding atoms.
+// A structure is a pair of "units" and an element set.
+// Each unit contains the data and transformation of its corresponding elements.
 interface Structure {
 interface Structure {
     readonly units: ReadonlyArray<Unit>,
     readonly units: ReadonlyArray<Unit>,
-    readonly atoms: AtomSet
+    readonly elements: ElementSet
 }
 }
 
 
 namespace Structure {
 namespace Structure {
-    export function create(units: ReadonlyArray<Unit>, atoms: AtomSet): Structure { return { units, atoms }; }
-    export function Empty(units: ReadonlyArray<Unit>): Structure { return create(units, AtomSet.Empty); };
+    export function create(units: ReadonlyArray<Unit>, elements: ElementSet): Structure { return { units, elements }; }
+    export function Empty(units: ReadonlyArray<Unit>): Structure { return create(units, ElementSet.Empty); };
 
 
     export function ofData(format: Format) {
     export function ofData(format: Format) {
         const models = Model.create(format);
         const models = Model.create(format);
@@ -34,8 +34,8 @@ namespace Structure {
         const builder = Builder();
         const builder = Builder();
 
 
         for (let c = 0; c < chains.count; c++) {
         for (let c = 0; c < chains.count; c++) {
-            const group = AtomGroup.createNew(OrderedSet.ofBounds(chains.segments[c], chains.segments[c + 1]));
-            const unit = Unit.create(model, SymmetryOperator.Default, group);
+            const group = ElementGroup.createNew(OrderedSet.ofBounds(chains.segments[c], chains.segments[c + 1]));
+            const unit = Unit.createAtomic(model, SymmetryOperator.Default, group);
             builder.add(unit, unit.fullGroup);
             builder.add(unit, unit.fullGroup);
         }
         }
 
 
@@ -43,38 +43,38 @@ namespace Structure {
     }
     }
 
 
     export interface Builder {
     export interface Builder {
-        add(unit: Unit, atoms: AtomGroup): void,
+        add(unit: Unit, elements: ElementGroup): void,
         addUnit(unit: Unit): void,
         addUnit(unit: Unit): void,
-        setAtoms(unitId: number, atoms: AtomGroup): void,
+        setElements(unitId: number, elements: ElementGroup): void,
         getStructure(): Structure,
         getStructure(): Structure,
-        readonly atomCount: number
+        readonly elementCount: number
     }
     }
 
 
     class BuilderImpl implements Builder {
     class BuilderImpl implements Builder {
         private _unitId = 0;
         private _unitId = 0;
         private units: Unit[] = [];
         private units: Unit[] = [];
-        private atoms = AtomSet.Generator();
-        atomCount = 0;
+        private elements = ElementSet.Generator();
+        elementCount = 0;
 
 
-        add(unit: Unit, atoms: AtomGroup) { const id = this.addUnit(unit); this.setAtoms(id, atoms); }
+        add(unit: Unit, elements: ElementGroup) { const id = this.addUnit(unit); this.setElements(id, elements); }
         addUnit(unit: Unit) { const id = this._unitId++; this.units[id] = unit; return id; }
         addUnit(unit: Unit) { const id = this._unitId++; this.units[id] = unit; return id; }
-        setAtoms(unitId: number, atoms: AtomGroup) { this.atoms.add(unitId, atoms); this.atomCount += AtomGroup.size(atoms); }
-        getStructure(): Structure { return this.atomCount > 0 ? Structure.create(this.units, this.atoms.getSet()) : Empty(this.units); }
+        setElements(unitId: number, elements: ElementGroup) { this.elements.add(unitId, elements); this.elementCount += ElementGroup.size(elements); }
+        getStructure(): Structure { return this.elementCount > 0 ? Structure.create(this.units, this.elements.getSet()) : Empty(this.units); }
     }
     }
 
 
     export function Builder(): Builder { return new BuilderImpl(); }
     export function Builder(): Builder { return new BuilderImpl(); }
 
 
     /** Transient = location gets overwritten when move() is called. */
     /** Transient = location gets overwritten when move() is called. */
-    export function atomLocationsTransient(s: Structure): Iterator<Atom.Location> {
-        const l = Atom.Location();
-        const update = Atom.updateLocation;
-        return Iterator.map(AtomSet.atoms(s.atoms), a => update(s, l, a));
+    export function elementLocationsTransient(s: Structure): Iterator<Element.Location> {
+        const l = Element.Location();
+        const update = Element.updateLocation;
+        return Iterator.map(ElementSet.elements(s.elements), a => update(s, l, a));
     }
     }
 
 
     export function getModels(s: Structure) {
     export function getModels(s: Structure) {
-        const { units, atoms } = s;
+        const { units, elements } = s;
         const arr = UniqueArray.create<Model['id'], Model>();
         const arr = UniqueArray.create<Model['id'], Model>();
-        const ids = AtomSet.unitIds(atoms);
+        const ids = ElementSet.unitIds(elements);
         for (let i = 0; i < ids.length; i++) {
         for (let i = 0; i < ids.length; i++) {
             const u = units[ids[i]];
             const u = units[ids[i]];
             UniqueArray.add(arr, u.model.id, u.model);
             UniqueArray.add(arr, u.model.id, u.model);

+ 4 - 4
src/mol-model/structure/structure/symmetry.ts

@@ -5,7 +5,7 @@
  */
  */
 
 
 import Structure from './structure'
 import Structure from './structure'
-import AtomSet from './atom/set'
+import ElementSet from './element/set'
 import Unit from './unit'
 import Unit from './unit'
 import { Selection } from '../query'
 import { Selection } from '../query'
 import { ModelSymmetry } from '../model'
 import { ModelSymmetry } from '../model'
@@ -28,14 +28,14 @@ function buildAssemblyImpl(structure: Structure, name: string) {
     for (const g of assembly.operatorGroups) {
     for (const g of assembly.operatorGroups) {
         const selection = g.selector(structure);
         const selection = g.selector(structure);
         if (Selection.structureCount(selection) === 0) continue;
         if (Selection.structureCount(selection) === 0) continue;
-        const { units, atoms } = Selection.unionStructure(selection);
+        const { units, elements } = Selection.unionStructure(selection);
 
 
-        const unitIds = AtomSet.unitIds(atoms);
+        const unitIds = ElementSet.unitIds(elements);
 
 
         for (const oper of g.operators) {
         for (const oper of g.operators) {
             for (let uI = 0, _uI = unitIds.length; uI < _uI; uI++) {
             for (let uI = 0, _uI = unitIds.length; uI < _uI; uI++) {
                 const unit = units[unitIds[uI]];
                 const unit = units[unitIds[uI]];
-                assembler.add(Unit.withOperator(unit, oper), AtomSet.unitGetByIndex(atoms, uI));
+                assembler.add(Unit.withOperator(unit, oper), ElementSet.unitGetByIndex(elements, uI));
             }
             }
         }
         }
     }
     }

+ 56 - 31
src/mol-model/structure/structure/unit.ts

@@ -5,44 +5,62 @@
  */
  */
 
 
 import SymmetryOperator from 'mol-math/geometry/symmetry-operator'
 import SymmetryOperator from 'mol-math/geometry/symmetry-operator'
-import AtomGroup from './atom/group'
+import ElementGroup from './element/group'
 import { Model } from '../model'
 import { Model } from '../model'
 
 
-// A bulding block of a structure that corresponds
-// to a "natural group of atoms" (most often a "chain")
-// together with a tranformation (rotation and translation)
-// that is dynamically applied to the underlying atom set.
-//
-// An atom set can be referenced by multiple diffrent units which
-// makes construction of assemblies and spacegroups very efficient.
-interface Unit extends SymmetryOperator.ArrayMapping {
-    // Provides access to the underlying data.
-    readonly model: Model,
-
-    // The "full" atom group corresponding to this unit.
-    // Every selection is a subset of this atoms group.
-    // Things like inter-unit bonds or spatial lookups
-    // can be be implemented efficiently as "views" of the
-    // full group.
-    readonly fullGroup: AtomGroup,
-
-    // Reference some commonly accessed things for faster access.
-    readonly residueIndex: ArrayLike<number>,
-    readonly chainIndex: ArrayLike<number>,
-    readonly hierarchy: Model['hierarchy'],
-    readonly conformation: Model['conformation']
-
-    // TODO: add velocity?
-    // AR: would fit into conformation, right?
-}
+// A building block of a structure that corresponds to an atomic or a coarse grained representation
+// 'conveniently grouped together'.
+type Unit = Unit.Atomic | Unit.Coarse
 
 
 namespace Unit {
 namespace Unit {
-    export function create(model: Model, operator: SymmetryOperator, fullGroup: AtomGroup): Unit {
+    export const enum Kind { Atomic, Coarse }
+
+    export function isAtomic(u: Unit): u is Atomic { return u.kind === Kind.Atomic; }
+    export function isCoarse(u: Unit): u is Coarse { return u.kind === Kind.Coarse; }
+
+    export interface Base extends SymmetryOperator.ArrayMapping {
+        // Provides access to the underlying data.
+        readonly model: Model,
+
+        // The "full" atom group corresponding to this unit.
+        // Every selection is a subset of this atoms group.
+        // Things like inter-unit bonds or spatial lookups
+        // can be be implemented efficiently as "views" of the
+        // full group.
+        readonly fullGroup: ElementGroup,
+
+        readonly hierarchy: Model['hierarchy'],
+    }
+
+    // A bulding block of a structure that corresponds
+    // to a "natural group of atoms" (most often a "chain")
+    // together with a tranformation (rotation and translation)
+    // that is dynamically applied to the underlying atom set.
+    //
+    // An atom set can be referenced by multiple diffrent units which
+    // makes construction of assemblies and spacegroups very efficient.
+    export interface Atomic extends Base {
+        readonly kind: Unit.Kind.Atomic,
+
+        // Reference some commonly accessed things for faster access.
+        readonly residueIndex: ArrayLike<number>,
+        readonly chainIndex: ArrayLike<number>,
+        readonly conformation: Model['conformation']
+    }
+
+    // Coarse grained representations.
+    // TODO: can we use the ArrayMapping here?
+    export interface Coarse extends Base  {
+        readonly kind: Unit.Kind.Coarse
+    }
+
+    export function createAtomic(model: Model, operator: SymmetryOperator, fullGroup: ElementGroup): Unit {
         const h = model.hierarchy;
         const h = model.hierarchy;
         const { invariantPosition, position, x, y, z } = SymmetryOperator.createMapping(operator, model.conformation);
         const { invariantPosition, position, x, y, z } = SymmetryOperator.createMapping(operator, model.conformation);
 
 
         return {
         return {
             model,
             model,
+            kind: Kind.Atomic,
             operator,
             operator,
             fullGroup,
             fullGroup,
             residueIndex: h.residueSegments.segmentMap,
             residueIndex: h.residueSegments.segmentMap,
@@ -55,8 +73,15 @@ namespace Unit {
         };
         };
     }
     }
 
 
-    export function withOperator(unit: Unit, operator: SymmetryOperator) {
-        return create(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup);
+    export function createCoarse(model: Model, operator: SymmetryOperator, fullGroup: ElementGroup): Unit {
+        throw 'not implemented'
+    }
+
+    export function withOperator(unit: Unit, operator: SymmetryOperator): Unit {
+        switch (unit.kind) {
+            case Kind.Atomic: return createAtomic(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup);
+            case Kind.Coarse: return createCoarse(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup);
+        }
     }
     }
 }
 }
 
 

+ 7 - 7
src/perf-tests/chunked-array-vs-native.ts

@@ -7,7 +7,7 @@ function testNative(size: number) {
     return xs;
     return xs;
 }
 }
 
 
-function testChunkedTyped(size: number, chunk: number, linear: boolean) {
+function testChunkedTyped(size: number, chunk: number) {
     const xs = ChunkedArray.create(s => new Int32Array(s), 1, chunk);
     const xs = ChunkedArray.create(s => new Int32Array(s), 1, chunk);
     for (let i = 0; i < size; i++) ChunkedArray.add(xs, i * i);
     for (let i = 0; i < size; i++) ChunkedArray.add(xs, i * i);
     return ChunkedArray.compact(xs);
     return ChunkedArray.compact(xs);
@@ -25,12 +25,12 @@ const N = 70000;
 
 
 suite
 suite
     .add('native', () => testNative(N))
     .add('native', () => testNative(N))
-    .add('chunkedT 0.1k', () => testChunkedTyped(N, 100, false))
-    .add('chunkedT 4k', () => testChunkedTyped(N, 4096, false))
-    .add('chunkedT 4k lin', () => testChunkedTyped(N, 4096, true))
-    .add('chunkedT N / 2', () => testChunkedTyped(N, N / 2, false))
-    .add('chunkedT N', () => testChunkedTyped(N, N, false))
-    .add('chunkedT 2 * N', () => testChunkedTyped(N, 2 * N, false))
+    // .add('chunkedT 0.1k', () => testChunkedTyped(N, 100, false))
+    // .add('chunkedT 4k', () => testChunkedTyped(N, 4096, false))
+    .add('chunkedT 4k lin', () => testChunkedTyped(N, 4096))
+    // .add('chunkedT N / 2', () => testChunkedTyped(N, N / 2, false))
+    // .add('chunkedT N', () => testChunkedTyped(N, N, false))
+    // .add('chunkedT 2 * N', () => testChunkedTyped(N, 2 * N, false))
 
 
     .add('chunkedN N', () => testChunkedNative(N, N))
     .add('chunkedN N', () => testChunkedNative(N, N))
     .add('chunkedN 0.1k', () => testChunkedNative(N, 100))
     .add('chunkedN 0.1k', () => testChunkedNative(N, 100))

+ 10 - 10
src/perf-tests/sets.ts

@@ -1,6 +1,6 @@
 import * as B from 'benchmark'
 import * as B from 'benchmark'
 import { Tuple, Segmentation, OrderedSet as OrdSet } from 'mol-data/int'
 import { Tuple, Segmentation, OrderedSet as OrdSet } from 'mol-data/int'
-import { AtomSet } from 'mol-model/structure'
+import { ElementSet } from 'mol-model/structure'
 
 
 // export namespace Iteration {
 // export namespace Iteration {
 //     const U = 1000, V = 2500;
 //     const U = 1000, V = 2500;
@@ -15,7 +15,7 @@ import { AtomSet } from 'mol-model/structure'
 //         }
 //         }
 //         sets[i * i] = OrdSet.ofSortedArray(set);
 //         sets[i * i] = OrdSet.ofSortedArray(set);
 //     }
 //     }
-//     const ms = AtomSet.create(sets);
+//     const ms = ElementSet.create(sets);
 
 
 //     export function native() {
 //     export function native() {
 //         let s = 0;
 //         let s = 0;
@@ -25,7 +25,7 @@ import { AtomSet } from 'mol-model/structure'
 
 
 //     export function iterators() {
 //     export function iterators() {
 //         let s = 0;
 //         let s = 0;
-//         const it = AtomSet.atoms(ms);
+//         const it = ElementSet.atoms(ms);
 //         while (it.hasNext) {
 //         while (it.hasNext) {
 //             const v = it.move();
 //             const v = it.move();
 //             s += Tuple.snd(v);
 //             s += Tuple.snd(v);
@@ -35,15 +35,15 @@ import { AtomSet } from 'mol-model/structure'
 
 
 //     export function elementAt() {
 //     export function elementAt() {
 //         let s = 0;
 //         let s = 0;
-//         for (let i = 0, _i = AtomSet.atomCount(ms); i < _i; i++) s += Tuple.snd(AtomSet.atomGetAt(ms, i));
+//         for (let i = 0, _i = ElementSet.atomCount(ms); i < _i; i++) s += Tuple.snd(ElementSet.atomGetAt(ms, i));
 //         return s;
 //         return s;
 //     }
 //     }
 
 
 //     export function manual() {
 //     export function manual() {
 //         let s = 0;
 //         let s = 0;
-//         const keys = AtomSet.unitIds(ms);
+//         const keys = ElementSet.unitIds(ms);
 //         for (let i = 0, _i = OrdSet.size(keys); i < _i; i++) {
 //         for (let i = 0, _i = OrdSet.size(keys); i < _i; i++) {
-//             const set = AtomSet.unitGetById(ms, OrdSet.getAt(keys, i));
+//             const set = ElementSet.unitGetById(ms, OrdSet.getAt(keys, i));
 //             for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
 //             for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
 //                 s += OrdSet.getAt(set, j);
 //                 s += OrdSet.getAt(set, j);
 //             }
 //             }
@@ -53,8 +53,8 @@ import { AtomSet } from 'mol-model/structure'
 
 
 //     export function manual1() {
 //     export function manual1() {
 //         let s = 0;
 //         let s = 0;
-//         for (let i = 0, _i = AtomSet.unitCount(ms); i < _i; i++) {
-//             const set = AtomSet.unitGetByIndex(ms, i);
+//         for (let i = 0, _i = ElementSet.unitCount(ms); i < _i; i++) {
+//             const set = ElementSet.unitGetByIndex(ms, i);
 //             for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
 //             for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
 //                 s += OrdSet.getAt(set, j);
 //                 s += OrdSet.getAt(set, j);
 //             }
 //             }
@@ -200,7 +200,7 @@ export namespace Union {
 
 
 export namespace Build {
 export namespace Build {
     function createSorted() {
     function createSorted() {
-        const b = AtomSet.LinearBuilder(AtomSet.Empty);
+        const b = ElementSet.LinearBuilder(ElementSet.Empty);
         for (let i = 0; i < 10; i++) {
         for (let i = 0; i < 10; i++) {
             for (let j = 0; j < 1000; j++) {
             for (let j = 0; j < 1000; j++) {
                 b.add(i, j);
                 b.add(i, j);
@@ -210,7 +210,7 @@ export namespace Build {
     }
     }
 
 
     function createByUnit() {
     function createByUnit() {
-        const b = AtomSet.LinearBuilder(AtomSet.Empty);
+        const b = ElementSet.LinearBuilder(ElementSet.Empty);
         for (let i = 0; i < 10; i++) {
         for (let i = 0; i < 10; i++) {
             b.beginUnit();
             b.beginUnit();
             for (let j = 0; j < 1000; j++) {
             for (let j = 0; j < 1000; j++) {

+ 79 - 79
src/perf-tests/structure.ts

@@ -11,7 +11,7 @@ import * as fs from 'fs'
 import fetch from 'node-fetch'
 import fetch from 'node-fetch'
 import CIF from 'mol-io/reader/cif'
 import CIF from 'mol-io/reader/cif'
 
 
-import { Structure, Model, Queries as Q, Atom, AtomGroup, AtomSet, Selection, Symmetry } from 'mol-model/structure'
+import { Structure, Model, Queries as Q, Element, ElementGroup, ElementSet, Selection, Symmetry } from 'mol-model/structure'
 import { Segmentation } from 'mol-data/int'
 import { Segmentation } from 'mol-data/int'
 
 
 import to_mmCIF from 'mol-model/structure/export/mmcif'
 import to_mmCIF from 'mol-model/structure/export/mmcif'
@@ -117,20 +117,20 @@ export namespace PropertyAccess {
         return s;
         return s;
     }
     }
 
 
-    function sumProperty(structure: Structure, p: Atom.Property<number>) {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
-        const l = Atom.Location();
+    function sumProperty(structure: Structure, p: Element.Property<number>) {
+        const { elements, units } = structure;
+        const unitIds = ElementSet.unitIds(elements);
+        const l = Element.Location();
 
 
         let s = 0;
         let s = 0;
 
 
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
             l.unit = units[unitIds[i]];
             l.unit = units[unitIds[i]];
-            const set = AtomSet.unitGetByIndex(atoms, i);
+            const set = ElementSet.unitGetByIndex(elements, i);
 
 
 
 
-            for (let j = 0, _j = AtomGroup.size(set); j < _j; j++) {
-                l.atom = AtomGroup.getAt(set, j);
+            for (let j = 0, _j = ElementGroup.size(set); j < _j; j++) {
+                l.element= ElementGroup.getAt(set, j);
                 s += p(l);
                 s += p(l);
             }
             }
         }
         }
@@ -138,10 +138,10 @@ export namespace PropertyAccess {
         return s;
         return s;
     }
     }
 
 
-    function sumPropertySegmented(structure: Structure, p: Atom.Property<number>) {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
-        const l = Atom.Location();
+    function sumPropertySegmented(structure: Structure, p: Element.Property<number>) {
+        const { elements, units } = structure;
+        const unitIds = ElementSet.unitIds(elements);
+        const l = Element.Location();
 
 
         let s = 0;
         let s = 0;
 
 
@@ -149,22 +149,22 @@ export namespace PropertyAccess {
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
         for (let i = 0, _i = unitIds.length; i < _i; i++) {
             const unit = units[unitIds[i]];
             const unit = units[unitIds[i]];
             l.unit = unit;
             l.unit = unit;
-            const set = AtomSet.unitGetByIndex(atoms, i);
+            const set = ElementSet.unitGetByIndex(elements, i);
 
 
-            const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set.atoms);
+            const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set.elements);
             const residues = unit.hierarchy.residueSegments;
             const residues = unit.hierarchy.residueSegments;
             while (chainsIt.hasNext) {
             while (chainsIt.hasNext) {
                 cC++;
                 cC++;
 
 
                 const chainSegment = chainsIt.move();
                 const chainSegment = chainsIt.move();
-                const residuesIt = Segmentation.transientSegments(residues, set.atoms, chainSegment);
+                const residuesIt = Segmentation.transientSegments(residues, set.elements, chainSegment);
                 while (residuesIt.hasNext) {
                 while (residuesIt.hasNext) {
                     rC++;
                     rC++;
                     const residueSegment = residuesIt.move();
                     const residueSegment = residuesIt.move();
-                    // l.atom = OrdSet.getAt(set, residueSegment.start);
+                    // l.element= OrdSet.getAt(set, residueSegment.start);
                     // console.log(unit.hierarchy.residues.auth_comp_id.value(unit.residueIndex[l.atom]), l.atom, OrdSet.getAt(set, residueSegment.end))
                     // console.log(unit.hierarchy.residues.auth_comp_id.value(unit.residueIndex[l.atom]), l.atom, OrdSet.getAt(set, residueSegment.end))
                     for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
                     for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
-                        l.atom = AtomGroup.getAt(set, j);
+                        l.element= ElementGroup.getAt(set, j);
                         vA++;
                         vA++;
                         s += p(l);
                         s += p(l);
                     }
                     }
@@ -177,37 +177,37 @@ export namespace PropertyAccess {
         return s;
         return s;
     }
     }
 
 
-    function sumPropertyResidue(structure: Structure, p: Atom.Property<number>) {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
-        const l = Atom.Location();
+    // function sumPropertyResidue(structure: Structure, p: Element.Property<number>) {
+    //     const { atoms, units } = structure;
+    //     const unitIds = ElementSet.unitIds(atoms);
+    //     const l = Element.Location();
 
 
-        let s = 0;
+    //     let s = 0;
 
 
-        for (let i = 0, _i = unitIds.length; i < _i; i++) {
-            const unit = units[unitIds[i]];
-            l.unit = unit;
-            const set = AtomSet.unitGetByIndex(atoms, i);
-            const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set.atoms);
-            while (residuesIt.hasNext) {
-                l.atom = AtomGroup.getAt(set, residuesIt.move().start);
-                s += p(l);
-            }
-        }
+    //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
+    //         const unit = units[unitIds[i]];
+    //         l.unit = unit;
+    //         const set = ElementSet.unitGetByIndex(atoms, i);
+    //         const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set.atoms);
+    //         while (residuesIt.hasNext) {
+    //             l.element= ElementGroup.getAt(set, residuesIt.move().start);
+    //             s += p(l);
+    //         }
+    //     }
 
 
-        return s;
-    }
+    //     return s;
+    // }
 
 
-    function sumPropertyAtomSetIt(structure: Structure, p: Atom.Property<number>) {
-        const { atoms, units } = structure;
+    function sumPropertyAtomSetIt(structure: Structure, p: Element.Property<number>) {
+        const { elements, units } = structure;
 
 
         let s = 0;
         let s = 0;
-        const atomsIt = AtomSet.atoms(atoms);
-        const l = Atom.Location();
+        const atomsIt = ElementSet.elements(elements);
+        const l = Element.Location();
         while (atomsIt.hasNext) {
         while (atomsIt.hasNext) {
             const a = atomsIt.move();
             const a = atomsIt.move();
-            l.unit = units[Atom.unit(a)];
-            l.atom = Atom.index(a);
+            l.unit = units[Element.unit(a)];
+            l.element= Element.index(a);
             s += p(l);
             s += p(l);
         }
         }
         return s;
         return s;
@@ -215,7 +215,7 @@ export namespace PropertyAccess {
 
 
     // function sumPropertySegmentedMutable(structure: Structure, p: Property<number>) {
     // function sumPropertySegmentedMutable(structure: Structure, p: Property<number>) {
     //     const { atoms, units } = structure;
     //     const { atoms, units } = structure;
-    //     const unitIds = AtomSet.unitIds(atoms);
+    //     const unitIds = ElementSet.unitIds(atoms);
     //     const l = Property.createLocation();
     //     const l = Property.createLocation();
 
 
     //     let s = 0;
     //     let s = 0;
@@ -223,7 +223,7 @@ export namespace PropertyAccess {
     //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
     //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
     //         const unit = units[unitIds[i]];
     //         const unit = units[unitIds[i]];
     //         l.unit = unit;
     //         l.unit = unit;
-    //         const set = AtomSet.unitGetByIndex(atoms, i);
+    //         const set = ElementSet.unitGetByIndex(atoms, i);
 
 
     //         const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set);
     //         const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set);
     //         const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set);
     //         const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set);
@@ -233,7 +233,7 @@ export namespace PropertyAccess {
     //             while (residuesIt.hasNext) {
     //             while (residuesIt.hasNext) {
     //                 const residueSegment = residuesIt.move();
     //                 const residueSegment = residuesIt.move();
     //                 for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
     //                 for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
-    //                     l.atom = OrdSet.getAt(set, j);
+    //                     l.element= OrdSet.getAt(set, j);
     //                     s += p(l);
     //                     s += p(l);
     //                 }
     //                 }
     //             }
     //             }
@@ -243,30 +243,30 @@ export namespace PropertyAccess {
     //     return s;
     //     return s;
     // }
     // }
 
 
-    function sumDirect(structure: Structure) {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
+    // function sumDirect(structure: Structure) {
+    //     const { atoms, units } = structure;
+    //     const unitIds = ElementSet.unitIds(atoms);
 
 
-        let s = 0;
+    //     let s = 0;
 
 
-        for (let i = 0, _i = unitIds.length; i < _i; i++) {
-            const unitId = unitIds[i];
-            const unit = units[unitId];
-            const set = AtomSet.unitGetByIndex(atoms, i);
-            //const { residueIndex, chainIndex } = unit;
-            const p = unit.conformation.atomId.value;
-            for (let j = 0, _j = AtomGroup.size(set); j < _j; j++) {
-                const aI = AtomGroup.getAt(set, j);
-                s += p(aI);
-            }
-        }
+    //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
+    //         const unitId = unitIds[i];
+    //         const unit = units[unitId];
+    //         const set = ElementSet.unitGetByIndex(atoms, i);
+    //         //const { residueIndex, chainIndex } = unit;
+    //         const p = unit.conformation.atomId.value;
+    //         for (let j = 0, _j = ElementGroup.size(set); j < _j; j++) {
+    //             const aI = ElementGroup.getAt(set, j);
+    //             s += p(aI);
+    //         }
+    //     }
 
 
-        return s;
-    }
+    //     return s;
+    // }
 
 
     // function concatProperty(structure: Structure, p: Property<string>) {
     // function concatProperty(structure: Structure, p: Property<string>) {
     //     const { atoms, units } = structure;
     //     const { atoms, units } = structure;
-    //     const unitIds = AtomSet.unitIds(atoms);
+    //     const unitIds = ElementSet.unitIds(atoms);
     //     const l = Property.createLocation(structure);
     //     const l = Property.createLocation(structure);
 
 
     //     let s = [];
     //     let s = [];
@@ -274,12 +274,12 @@ export namespace PropertyAccess {
     //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
     //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
     //         const unitId = unitIds[i];
     //         const unitId = unitIds[i];
     //         l.unit = units[unitId];
     //         l.unit = units[unitId];
-    //         const set = AtomSet.unitGetByIndex(atoms, i);
+    //         const set = ElementSet.unitGetByIndex(atoms, i);
     //         const { residueIndex, chainIndex } = l.unit;
     //         const { residueIndex, chainIndex } = l.unit;
 
 
     //         for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
     //         for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
     //             const aI = OrdSet.getAt(set, j);
     //             const aI = OrdSet.getAt(set, j);
-    //             l.atom = aI;
+    //             l.element= aI;
     //             l.residueIndex = residueIndex[aI];
     //             l.residueIndex = residueIndex[aI];
     //             l.chainIndex = chainIndex[aI];
     //             l.chainIndex = chainIndex[aI];
     //             s[s.length] = p(l);
     //             s[s.length] = p(l);
@@ -327,23 +327,23 @@ export namespace PropertyAccess {
         // return;
         // return;
 
 
         console.log('bs', baseline(models[0]));
         console.log('bs', baseline(models[0]));
-        console.log('sp', 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('sp', sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.element)));
+        console.log(sumPropertySegmented(structures[0], l => l.unit.model.conformation.atomId.value(l.element)));
 
 
-        //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(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.element));
+        console.log(sumPropertyAtomSetIt(structures[0], l => l.unit.model.conformation.atomId.value(l.element)));
         //console.log(sumProperty(structures[0], Property.cachedAtomColumn(m => m.conformation.atomId)));
         //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.atom])));
+        //console.log(sumDirect(structures[0]));
+        //console.log('r', sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])));
 
 
         console.time('atom.x');
         console.time('atom.x');
         console.log('atom.x', sumProperty(structures[0], Q.props.atom.x));
         console.log('atom.x', sumProperty(structures[0], Q.props.atom.x));
         console.timeEnd('atom.x');
         console.timeEnd('atom.x');
         console.time('__x')
         console.time('__x')
-        console.log('__x', sumProperty(structures[0], l => l.unit.conformation.x[l.atom]));
+        //console.log('__x', sumProperty(structures[0], l => l.unit.conformation.x[l.atom]));
         console.timeEnd('__x')
         console.timeEnd('__x')
 
 
-        //const authSeqId = Atom.property(l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom]));
+        //const authSeqId = Element.property(l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom]));
 
 
         //const auth_seq_id = Q.props.residue.auth_seq_id;
         //const auth_seq_id = Q.props.residue.auth_seq_id;
         const auth_comp_id = Q.props.residue.auth_comp_id;
         const auth_comp_id = Q.props.residue.auth_comp_id;
@@ -381,21 +381,21 @@ export namespace PropertyAccess {
             //.add('test q', () => q(structures[0]))
             //.add('test q', () => q(structures[0]))
             .add('test q1', () => q1(structures[0]))
             .add('test q1', () => q1(structures[0]))
             .add('test q3', () => q3(structures[0]))
             .add('test q3', () => q3(structures[0]))
-            //.add('test int', () => sumProperty(structures[0], l => col(l.atom)))
+            //.add('test int', () => sumProperty(structures[0], l => col(l.element))
             // .add('sum residue', () => sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])))
             // .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('baseline', () =>  baseline(models[0]))
             // .add('direct', () =>  sumDirect(structures[0]))
             // .add('direct', () =>  sumDirect(structures[0]))
-            //.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('normal int', () => sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.element))
+            //.add('atom set it int', () => sumPropertyAtomSetIt(structures[0], l => l.unit.conformation.atomId.value(l.element))
+            // .add('segmented faster int', () => sumPropertySegmented(structures[0], l => l.unit.conformation.atomId.value(l.element))
+            // .add('faster int', () => sumProperty(structures[0], l => l.unit.conformation.atomId.value(l.element))
             //.add('segmented faster _x', () => sumPropertySegmented(structures[0], l => l.unit.conformation.__x[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('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('segmented mut faster int', () => sumPropertySegmentedMutable(structures[0], l => l.unit.conformation.atomId.value(l.element))
+            //.add('normal shortcut int', () => sumProperty(structures[0], l => l.conformation.atomId.value(l.element))
             //.add('cached int', () => sumProperty(structures[0], Property.cachedAtomColumn(m => m.conformation.atomId)))
             //.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.atom)))
+            //.add('concat str', () => concatProperty(structures[0], l => l.unit.model.hierarchy.atoms.auth_atom_id.value(l.element))
             //.add('cached concat str', () => concatProperty(structures[0], Property.cachedAtomColumn(m => m.hierarchy.atoms.auth_atom_id)))
             //.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)))
             .on('cycle', (e: any) => console.log(String(e.target)))
             .run();
             .run();