diff --git a/src/mol-math/geometry/symmetry-operator.ts b/src/mol-math/geometry/symmetry-operator.ts
index d0065a740df3b01a91989834aa12e017e0a9fe7c..dcc83ade56b232b7fa5a0d208aff3d57b76aaeb8 100644
--- a/src/mol-math/geometry/symmetry-operator.ts
+++ b/src/mol-math/geometry/symmetry-operator.ts
@@ -38,6 +38,7 @@ namespace SymmetryOperator {
 
     export interface CoordinateMapper { (index: number, slot: Vec3): Vec3 }
     export interface ArrayMapping {
+        readonly operator: SymmetryOperator,
         readonly invariantPosition: CoordinateMapper,
         readonly position: CoordinateMapper,
         x(index: number): number,
diff --git a/src/mol-model/structure/query/generators.ts b/src/mol-model/structure/query/generators.ts
index 024400c963aac77ecb05bdff04fa4f2b8e083781..d911c167ba5fd23448eb9fb8dad0ca83777ca4bb 100644
--- a/src/mol-model/structure/query/generators.ts
+++ b/src/mol-model/structure/query/generators.ts
@@ -10,7 +10,7 @@ import P from './properties'
 import { Structure, AtomSet, Atom } from '../structure'
 import { OrderedSet, Segmentation } from 'mol-data/int'
 
-export const all: Query = s => s;
+export const all: Query = s => Selection.Singletons(s, s.atoms);
 
 export interface AtomGroupsParams {
     entityTest: Atom.Predicate,
@@ -56,7 +56,7 @@ function atomGroupsLinear(atomTest: Atom.Predicate): Query {
             builder.commitUnit(unitId);
         }
 
-        return Structure.create(units, builder.getSet());
+        return Selection.Singletons(structure, builder.getSet());
     };
 }
 
@@ -99,7 +99,7 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
             builder.commitUnit(unitId);
         }
 
-        return Structure.create(units, builder.getSet());
+        return Selection.Singletons(structure, builder.getSet());
     };
 }
 
@@ -124,27 +124,27 @@ class LinearGroupingBuilder {
         return true;
     }
 
-    private singletonStructure(): Structure {
+    private singletonSelection(): Selection {
         const atoms: Atom[] = Atom.createEmptyArray(this.builders.length);
         for (let i = 0, _i = this.builders.length; i < _i; i++) {
             atoms[i] = this.builders[i].singleton();
         }
-        return Structure.create(this.structure.units, AtomSet.ofAtoms(atoms, this.structure.atoms));
+        return Selection.Singletons(this.structure, AtomSet.ofAtoms(atoms, this.structure.atoms));
     }
 
     private fullSelection() {
-        const ret: Structure[] = [];
+        const sets: AtomSet[] = [];
         for (let i = 0, _i = this.builders.length; i < _i; i++) {
-            ret[i] = Structure.create(this.structure.units, this.builders[i].getSet());
+            sets[i] = this.builders[i].getSet();
         }
-        return ret;
+        return Selection.Seq(this.structure, sets);
     }
 
     getSelection(): Selection {
         const len = this.builders.length;
-        if (len === 0) return Selection.Empty;
-        if (len === 1) return Structure.create(this.structure.units, this.builders[0].getSet());
-        if (this.allSingletons()) return this.singletonStructure();
+        if (len === 0) return Selection.Empty(this.structure);
+        if (len === 1) return Selection.Singletons(this.structure, this.builders[0].getSet());
+        if (this.allSingletons()) return this.singletonSelection();
         return this.fullSelection();
     }
 
diff --git a/src/mol-model/structure/query/selection.ts b/src/mol-model/structure/query/selection.ts
index 1bb2b5776f74e3a719f0e6fe98b7414e2974751f..f119cd120415cb14204cd658d82bae29feadd1b3 100644
--- a/src/mol-model/structure/query/selection.ts
+++ b/src/mol-model/structure/query/selection.ts
@@ -4,131 +4,94 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import Iterator from 'mol-data/iterator'
 import { HashSet } from 'mol-data/util'
-import { Structure, Atom, AtomSet } from '../structure'
+import { Structure, AtomSet } from '../structure'
 
-type Selection =
-    | Structure // each atom is interpreted as a singleton structure
-    | Structure[]
-
-// TODO: Do not allow to change unit set in the middle of a query, create a differnt language to control assemblies etc.
-/*
-type Selection =
-  | { kind: 'sequence', structure: Structure, sets: AtomSet[] }
-  | { kind: 'atom-set', structure: Structure, set: AtomSet }
-
-  structure allows for good unions.
-*/
+// A selection is a pair of a Structure and a sequence of unique AtomSets
+type Selection = Selection.Singletons | Selection.Seq
 
 namespace Selection {
-    export const Empty: Selection = [];
+    // 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 Seq { readonly kind: 'seq', readonly structure: Structure, readonly sets: ReadonlyArray<AtomSet> }
 
-    function isStructure(x: Selection): x is Structure { return !!(x as Structure).units && !!(x as Structure).atoms; }
+    export function Singletons(structure: Structure, set: AtomSet): Singletons { return { kind: 'singletons', structure, set } }
+    export function Seq(structure: Structure, sets: AtomSet[]): Seq { return { kind: 'seq', structure, sets } }
 
-    export const isOfSingletons = isStructure
+    export function Empty(structure: Structure): Selection { return Seq(structure, []); };
 
-    export function structureCount(sel: Selection) {
-        if (isStructure(sel)) return AtomSet.atomCount(sel.atoms);
-        return sel.length;
-    }
+    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 union(sel: Selection): Structure {
-        if (isStructure(sel)) return sel;
-        if (!sel.length) return Structure.Empty;
-        const sets = [];
-        for (let i = 0, _i = sel.length; i < _i; i++) sets[sets.length] = sel[i].atoms;
-        return Structure.create(unionUnits(sel), AtomSet.union(sets, AtomSet.Empty));
+    export function structureCount(sel: Selection) {
+        if (isSingleton(sel)) return AtomSet.atomCount(sel.set);
+        return sel.sets.length;
     }
 
-    export function structures(sel: Selection): Iterator<Structure> {
-        if (isStructure(sel)) {
-            const units = sel.units;
-            return Iterator.map<Atom, Structure>(AtomSet.atoms(sel.atoms), atoms => Structure.create(units, atoms));
-        }
-        return Iterator.Array(sel);
+    export function unionStructure(sel: Selection): Structure {
+        if (isEmpty(sel)) return Structure.Empty(sel.structure.units);
+        if (isSingleton(sel)) return Structure.create(sel.structure.units, sel.set);
+        return Structure.create(sel.structure.units, AtomSet.union(sel.sets, sel.structure.atoms));
     }
 
     export function getAt(sel: Selection, i: number): Structure {
-        if (isStructure(sel)) {
-            return Structure.create(sel.units, AtomSet.atomGetAt(sel.atoms, i));
+        if (isSingleton(sel)) {
+            const atom = AtomSet.atomGetAt(sel.set, i);
+            return Structure.create(sel.structure.units, AtomSet.ofAtoms([atom], sel.structure.atoms));
         }
-        return sel[i];
+        return Structure.create(sel.structure.units, sel.sets[i]);
     }
 
     export interface Builder {
-        add(s: Structure): void,
+        add(set: AtomSet): void,
         getSelection(): Selection
     }
 
+    function getSelection(structure: Structure, sets: AtomSet[], allSingletons: boolean) {
+        const len = sets.length;
+        if (len === 0) return Empty(structure);
+        if (len === 1) return Singletons(structure, sets[0]);
+        if (allSingletons) return Singletons(structure, AtomSet.union(sets, structure.atoms));
+        return Seq(structure, sets);
+    }
+
     class LinearBuilderImpl implements Builder {
-        private structures: Structure[] = [];
+        private sets: AtomSet[] = [];
         private allSingletons = true;
 
-        add(s: Structure) {
-            const atomCount = AtomSet.atomCount(s.atoms);
+        add(atoms: AtomSet) {
+            const atomCount = AtomSet.atomCount(atoms);
             if (atomCount === 0) return;
-            this.structures[this.structures.length] = s;
+            this.sets[this.sets.length] = atoms;
             if (atomCount !== 1) this.allSingletons = false;
         }
 
-        getSelection() {
-            const len = this.structures.length;
-            if (len === 0) return Empty;
-            if (len === 1) return this.structures[0];
-            if (this.allSingletons) return union(this.structures);
-            return this.structures;
-        }
+        getSelection() { return getSelection(this.structure, this.sets, this.allSingletons); }
 
-        constructor() { }
+        constructor(private structure: Structure) { }
     }
 
     class HashBuilderImpl implements Builder {
-        private structures: Structure[] = [];
+        private sets: AtomSet[] = [];
         private allSingletons = true;
-        private sets = HashSet(AtomSet.hashCode, AtomSet.areEqual);
+        private uniqueSets = HashSet(AtomSet.hashCode, AtomSet.areEqual);
 
-        add(s: Structure) {
-            const atomCount = AtomSet.atomCount(s.atoms);
-            if (atomCount === 0 || !this.sets.add(s.atoms)) return;
-            this.structures[this.structures.length] = s;
+        add(atoms: AtomSet) {
+            const atomCount = AtomSet.atomCount(atoms);
+            if (atomCount === 0 || !this.uniqueSets.add(atoms)) return;
+            this.sets[this.sets.length] = atoms;
             if (atomCount !== 1) this.allSingletons = false;
         }
 
-        getSelection() {
-            const len = this.structures.length;
-            if (len === 0) return Empty;
-            if (len === 1) return this.structures[0];
-            if (this.allSingletons) return union(this.structures);
-            return this.structures;
-        }
+        getSelection() { return getSelection(this.structure, this.sets, this.allSingletons); }
 
-        constructor() { }
+        constructor(private structure: Structure) { }
     }
 
-    export function LinearBuilder(): Builder { return new LinearBuilderImpl(); }
-    export function UniqueBuilder(): Builder { return new HashBuilderImpl(); }
+    export function LinearBuilder(structure: Structure): Builder { return new LinearBuilderImpl(structure); }
+    export function UniqueBuilder(structure: Structure): Builder { return new HashBuilderImpl(structure); }
 
     // TODO: spatial lookup
 }
 
-export default Selection
-
-function unionUnits(xs: Structure[]): Structure['units'] {
-    return xs[0].units;
-//    let prev = xs[0].units;
-    // let sameUnits = true;
-    // for (let i = 1, _i = xs.length; i < _i; i++) {
-    //     if (xs[i].units !== prev) sameUnits = false;
-    // }
-    // if (sameUnits) return prev;
-
-    // const ret = [...prev];
-    // for (let i = 1, _i = xs.length; i < _i; i++) {
-    //     const units = xs[i].units;
-    //     if (units !== prev) IntMap.addFrom(ret, units);
-    //     prev = units;
-    // }
-
-    //return ret;
-}
+export default Selection
\ No newline at end of file
diff --git a/src/mol-model/structure/structure/atom/group.ts b/src/mol-model/structure/structure/atom/group.ts
index 22421f10e3794b757e0f583c3f860cdaa0e67a97..63228158aa1e4c05481ba9ae2e1e8ae27e3ac7e3 100644
--- a/src/mol-model/structure/structure/atom/group.ts
+++ b/src/mol-model/structure/structure/atom/group.ts
@@ -24,7 +24,7 @@ namespace AtomGroup {
     }
 
     export function create(unit: Unit, atoms: OrderedSet): AtomGroup {
-        if (OrderedSet.areEqual(atoms, unit.naturalGroup.atoms)) return unit.naturalGroup;
+        if (OrderedSet.areEqual(atoms, unit.fullGroup.atoms)) return unit.fullGroup;
         return createNew(atoms);
     }
 
diff --git a/src/mol-model/structure/structure/atom/set.ts b/src/mol-model/structure/structure/atom/set.ts
index 2c30cec4435d9346d73e26fa521172aacb959189..a50f79db70c37fafb37fdecc0f67533fdd1e40e8 100644
--- a/src/mol-model/structure/structure/atom/set.ts
+++ b/src/mol-model/structure/structure/atom/set.ts
@@ -34,7 +34,7 @@ namespace AtomSet {
     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: AtomSet[], template: AtomSet) => AtomSet = Impl.unionMany 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;
 
diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts
index c4346b036abc4836aae38959a2cc2db54ae3ff54..6cac5a7b8c4e05f9fdfc96abb12e902f68ae7bda 100644
--- a/src/mol-model/structure/structure/structure.ts
+++ b/src/mol-model/structure/structure/structure.ts
@@ -13,18 +13,16 @@ import AtomSet from './atom/set'
 import AtomGroup from './atom/group'
 import Atom from './atom'
 
-
-interface Structure extends Readonly<{
-    units: Unit[],
-    atoms: AtomSet
-}> { }
+// A structure is a pair of "units" and an atom set.
+// Each unit contains the data and transformation of its corresponding atoms.
+interface Structure {
+    readonly units: ReadonlyArray<Unit>,
+    readonly atoms: AtomSet
+}
 
 namespace Structure {
-    export const Empty: Structure = { units: [], atoms: AtomSet.Empty };
-
-    export function create(units: Unit[], atoms: AtomSet): Structure {
-        return { units, atoms };
-    }
+    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 ofData(format: Format) {
         const models = Model.create(format);
@@ -38,7 +36,7 @@ namespace Structure {
         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);
-            builder.add(unit, unit.naturalGroup);
+            builder.add(unit, unit.fullGroup);
         }
 
         return builder.getStructure();
@@ -61,7 +59,7 @@ namespace Structure {
         add(unit: Unit, atoms: AtomGroup) { const id = this.addUnit(unit); this.setAtoms(id, atoms); }
         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; }
+        getStructure(): Structure { return this.atomCount > 0 ? Structure.create(this.units, this.atoms.getSet()) : Empty(this.units); }
     }
 
     export function Builder(): Builder { return new BuilderImpl(); }
diff --git a/src/mol-model/structure/structure/symmetry.ts b/src/mol-model/structure/structure/symmetry.ts
index 115a372b3dee129e335893f24a6dbda41eaede2a..d23962d722583bceb842bb2efa111ff7ea268926 100644
--- a/src/mol-model/structure/structure/symmetry.ts
+++ b/src/mol-model/structure/structure/symmetry.ts
@@ -28,7 +28,7 @@ function buildAssemblyImpl(structure: Structure, name: string) {
     for (const g of assembly.operatorGroups) {
         const selection = g.selector(structure);
         if (Selection.structureCount(selection) === 0) continue;
-        const { units, atoms } = Selection.union(selection);
+        const { units, atoms } = Selection.unionStructure(selection);
 
         const unitIds = AtomSet.unitIds(atoms);
 
diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts
index 05bc6315c26f0448be4c9cf568e5cdf478a4b243..2ec27b6ca0c2115af9388ee701ecaa1b6649f3cc 100644
--- a/src/mol-model/structure/structure/unit.ts
+++ b/src/mol-model/structure/structure/unit.ts
@@ -8,16 +8,23 @@ import SymmetryOperator from 'mol-math/geometry/symmetry-operator'
 import AtomGroup from './atom/group'
 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,
 
-    // Determines the operation applied to this unit.
-    // The transform and and inverse are baked into the "getPosition" function
-    readonly operator: SymmetryOperator,
-
     // The "full" atom group corresponding to this unit.
-    readonly naturalGroup: AtomGroup,
+    // 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>,
@@ -29,14 +36,14 @@ interface Unit extends SymmetryOperator.ArrayMapping {
 }
 
 namespace Unit {
-    export function create(model: Model, operator: SymmetryOperator, naturalGroup: AtomGroup): Unit {
+    export function create(model: Model, operator: SymmetryOperator, fullGroup: AtomGroup): Unit {
         const h = model.hierarchy;
         const { invariantPosition, position, x, y, z } = SymmetryOperator.createMapping(operator, model.conformation);
 
         return {
             model,
             operator,
-            naturalGroup,
+            fullGroup,
             residueIndex: h.residueSegments.segmentMap,
             chainIndex: h.chainSegments.segmentMap,
             hierarchy: model.hierarchy,
@@ -48,7 +55,7 @@ namespace Unit {
     }
 
     export function withOperator(unit: Unit, operator: SymmetryOperator) {
-        return create(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.naturalGroup);
+        return create(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup);
     }
 }
 
diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts
index 013f08ae0a1642a97a00f4c734034f70d4ade73b..4cb8ce453da97a58ff2b63ead4de33a5302d4b71 100644
--- a/src/perf-tests/structure.ts
+++ b/src/perf-tests/structure.ts
@@ -36,11 +36,9 @@ function *test() {
 
 async function runIt<T>(itP: () => IterableIterator<T>) {
     const it = itP();
-    let lastValue: T | undefined;
-    while(true) {
+    while (true) {
         const { value, done } = it.next();
         if (done) return value;
-        lastValue = value;
     }
 }