diff --git a/src/mol-base/collections/_spec/table.spec.ts b/src/mol-base/collections/_spec/table.spec.ts
index 537579793d9bcc799abc9443d854ed28f3f7e3aa..aa7662ab48736aad7e2be9c8c6c815c66dc4b6af 100644
--- a/src/mol-base/collections/_spec/table.spec.ts
+++ b/src/mol-base/collections/_spec/table.spec.ts
@@ -40,8 +40,9 @@ describe('column', () => {
         expect(numStr.toArray()).toEqual(['1', '2']);
     });
 
-    it('permutation', () => {
-        expect(Column.permutation(arr, [1, 0, 3, 2]).toArray()).toEqual([2, 1, 4, 3]);
+    it('view', () => {
+        expect(Column.view(arr, [1, 0, 3, 2]).toArray()).toEqual([2, 1, 4, 3]);
+        expect(Column.view(arr, [1, 3]).toArray()).toEqual([2, 4]);
     });
 
     it('map to array', () => {
diff --git a/src/mol-base/collections/column.ts b/src/mol-base/collections/column.ts
index 941e25afcc9a390b861d31bdc5744b45817d58c5..e510026600e82f5e08c7b7e739b159f492da262f 100644
--- a/src/mol-base/collections/column.ts
+++ b/src/mol-base/collections/column.ts
@@ -12,12 +12,13 @@ interface Column<T> {
     readonly rowCount: number,
     value(row: number): T,
     valueKind(row: number): Column.ValueKind,
-    toArray(params?: Column.ToArrayParams): ReadonlyArray<T>,
+    toArray(params?: Column.ToArrayParams<T>): ReadonlyArray<T>,
     areValuesEqual(rowA: number, rowB: number): boolean
 }
 
 namespace Column {
     export type Type<T = any> = Type.Str | Type.Int | Type.Float | Type.Vector | Type.Matrix | Type.Aliased<T>
+    export type ArrayCtor<T> = { new(size: number): ArrayLike<T> }
 
     export namespace Type {
         export type Str = { T: string, kind: 'str' }
@@ -37,8 +38,8 @@ namespace Column {
         export function aliased<T>(t: Type): Aliased<T> { return t as any as Aliased<T>; }
     }
 
-    export interface ToArrayParams {
-        array?: { new(size: number): ArrayLike<number> },
+    export interface ToArrayParams<T> {
+        array?: ArrayCtor<T>,
         start?: number,
         /** Last row (exclusive) */
         end?: number
@@ -85,7 +86,7 @@ namespace Column {
         return windowColumn(column, start, end);
     }
 
-    export function permutation<T>(column: Column<T>, indices: ArrayLike<number>, checkIndentity = true) {
+    export function view<T>(column: Column<T>, indices: ArrayLike<number>, checkIndentity = true) {
         return columnPermutation(column, indices, checkIndentity);
     }
 
@@ -94,12 +95,12 @@ namespace Column {
         return createFirstIndexMapOfColumn(column);
     }
 
-    export function mapToArray<T, S>(column: Column<T>, f: (v: T) => S, ctor?: { new(size: number): ArrayLike<number> }): ArrayLike<S> {
+    export function mapToArray<T, S>(column: Column<T>, f: (v: T) => S, ctor?: ArrayCtor<S>): ArrayLike<S> {
         return mapToArrayImpl(column, f, ctor || Array);
     }
 
     /** Makes the column backned by an array. Useful for columns that accessed often. */
-    export function asArrayColumn<T>(c: Column<T>, array?: ToArrayParams['array']): Column<T> {
+    export function asArrayColumn<T>(c: Column<T>, array?: ArrayCtor<T>): Column<T> {
         if (c['@array']) return c;
         if (!c.isDefined) return Undefined(c.rowCount, c['@type']) as any as Column<T>;
         return arrayColumn({ array: c.toArray({ array }), type: c['@type'] as any, valueKind: c.valueKind });
@@ -220,7 +221,8 @@ function windowFull<T>(c: Column<T>, start: number, end: number): Column<T> {
     };
 }
 
-function isIdentity(map: ArrayLike<number>) {
+function isIdentity(map: ArrayLike<number>, rowCount: number) {
+    if (map.length !== rowCount) return false;
     for (let i = 0, _i = map.length; i < _i; i++) {
         if (map[i] !== i) return false;
     }
@@ -229,22 +231,22 @@ function isIdentity(map: ArrayLike<number>) {
 
 function columnPermutation<T>(c: Column<T>, map: ArrayLike<number>, checkIdentity: boolean): Column<T> {
     if (!c.isDefined) return c;
-    if (checkIdentity && isIdentity(map)) return c;
-    if (!c['@array']) return permutationArray(c, map);
-    return permutationFull(c, map);
+    if (checkIdentity && isIdentity(map, c.rowCount)) return c;
+    if (!c['@array']) return arrayView(c, map);
+    return viewFull(c, map);
 }
 
-function permutationArray<T>(c: Column<T>, map: ArrayLike<number>): Column<T> {
+function arrayView<T>(c: Column<T>, map: ArrayLike<number>): Column<T> {
     const array = c['@array']!;
-    const ret = new (array as any).constructor(c.rowCount);
-    for (let i = 0, _i = c.rowCount; i < _i; i++) ret[i] = array[map[i]];
+    const ret = new (array as any).constructor(map.length);
+    for (let i = 0, _i = map.length; i < _i; i++) ret[i] = array[map[i]];
     return arrayColumn({ array: ret, type: c['@type'], valueKind: c.valueKind });
 }
 
-function permutationFull<T>(c: Column<T>, map: ArrayLike<number>): Column<T> {
+function viewFull<T>(c: Column<T>, map: ArrayLike<number>): Column<T> {
     const v = c.value, vk = c.valueKind, ave = c.areValuesEqual;
     const value: Column<T>['value'] = row => v(map[row]);
-    const rowCount = c.rowCount;
+    const rowCount = map.length;
     return {
         '@type': c['@type'],
         '@array': void 0,
@@ -261,20 +263,20 @@ function permutationFull<T>(c: Column<T>, map: ArrayLike<number>): Column<T> {
     };
 }
 
-function mapToArrayImpl<T, S>(c: Column<T>, f: (v: T) => S, ctor: { new(size: number): ArrayLike<number> }): ArrayLike<S> {
+function mapToArrayImpl<T, S>(c: Column<T>, f: (v: T) => S, ctor: Column.ArrayCtor<S>): ArrayLike<S> {
     const ret = new ctor(c.rowCount) as any;
     for (let i = 0, _i = c.rowCount; i < _i; i++) ret[i] = f(c.value(i));
     return ret;
 }
 
 export namespace ColumnHelpers {
-    export function getArrayBounds(rowCount: number, params?: Column.ToArrayParams) {
+    export function getArrayBounds(rowCount: number, params?: Column.ToArrayParams<any>) {
         const start = params && typeof params.start !== 'undefined' ? Math.max(Math.min(params.start, rowCount - 1), 0) : 0;
         const end = params && typeof params.end !== 'undefined' ? Math.min(params.end, rowCount) : rowCount;
         return { start, end };
     }
 
-    export function createArray(rowCount: number, params?: Column.ToArrayParams) {
+    export function createArray(rowCount: number, params?: Column.ToArrayParams<any>) {
         const c = params && typeof params.array !== 'undefined' ? params.array : Array;
         const { start, end } = getArrayBounds(rowCount, params);
         return { array: new c(end - start) as any[], start, end };
@@ -285,7 +287,7 @@ export namespace ColumnHelpers {
         return target;
     }
 
-    export function createAndFillArray(rowCount: number, value: (row: number) => any, params?: Column.ToArrayParams) {
+    export function createAndFillArray(rowCount: number, value: (row: number) => any, params?: Column.ToArrayParams<any>) {
         const { array, start } = createArray(rowCount, params);
         return fillArrayValues(value, array, start);
     }
@@ -294,7 +296,7 @@ export namespace ColumnHelpers {
         return !!data.buffer && typeof data.byteLength === 'number' && typeof data.BYTES_PER_ELEMENT === 'number';
     }
 
-    export function typedArrayWindow(data: any, params?: Column.ToArrayParams): ReadonlyArray<number> {
+    export function typedArrayWindow(data: any, params?: Column.ToArrayParams<any>): ReadonlyArray<number> {
         const { constructor, buffer, length, byteOffset, BYTES_PER_ELEMENT } = data;
         const { start, end } = getArrayBounds(length, params);
         if (start === 0 && end === length) return data;
diff --git a/src/mol-base/collections/integer/_spec/segmentation.spec.ts b/src/mol-base/collections/integer/_spec/segmentation.spec.ts
index c77fbb86ff81b0e8d7fbfacd27b64d2bcb9b8144..2c08ce9293b77d5c793f567ff457472d4a260530 100644
--- a/src/mol-base/collections/integer/_spec/segmentation.spec.ts
+++ b/src/mol-base/collections/integer/_spec/segmentation.spec.ts
@@ -19,12 +19,17 @@ describe('segments', () => {
         expect(p).toBe(Interval.ofBounds(0, 2))
     });
 
+    it('ofOffsetts', () => {
+        const p = Segmentation.ofOffsets([10, 12], Interval.ofBounds(10, 14));
+        expect(p.segments).toEqual(new Int32Array([0, 2, 4]))
+    });
+
     it('map', () => {
         const segs = Segmentation.create([0, 1, 2]);
         expect(segs.segmentMap).toEqual(new Int32Array([0, 1]));
         expect(Segmentation.getSegment(segs, 0)).toBe(0);
         expect(Segmentation.getSegment(segs, 1)).toBe(1);
-    })
+    });
 
     it('iteration', () => {
         const it = Segmentation.transientSegments(segs, data);
diff --git a/src/mol-base/collections/integer/impl/segmentation.ts b/src/mol-base/collections/integer/impl/segmentation.ts
index a821db8ae880befef3c9f668722ef22b3ec08a0f..254191098fcaaf6932cb653565b3ea4f08e20e81 100644
--- a/src/mol-base/collections/integer/impl/segmentation.ts
+++ b/src/mol-base/collections/integer/impl/segmentation.ts
@@ -10,7 +10,7 @@ import Interval from '../interval'
 import SortedArray from '../sorted-array'
 import Segs from '../segmentation'
 
-type Segmentation = { segments: SortedArray, segmentMap: ArrayLike<number>, count: number }
+type Segmentation = { segments: SortedArray, segmentMap: Int32Array, count: number }
 
 export function create(values: ArrayLike<number>): Segmentation {
     const segments = SortedArray.ofSortedArray(values);
@@ -24,6 +24,16 @@ export function create(values: ArrayLike<number>): Segmentation {
     return { segments, segmentMap, count: values.length - 1 };
 }
 
+export function ofOffsets(offsets: ArrayLike<number>, bounds: Interval): Segmentation {
+    const s = Interval.start(bounds);
+    const segments = new Int32Array(offsets.length + 1);
+    for (let i = 0, _i = offsets.length; i < _i; i++) {
+        segments[i] = offsets[i] - s;
+    }
+    segments[offsets.length] = Interval.end(bounds) - s;
+    return create(segments);
+}
+
 export function count({ count }: Segmentation) { return count; }
 export function getSegment({ segmentMap }: Segmentation, value: number) { return segmentMap[value]; }
 
diff --git a/src/mol-base/collections/integer/segmentation.ts b/src/mol-base/collections/integer/segmentation.ts
index 3be8cc7c345bc8be093020576abdbc21f55877f0..275b44f6dacc6e97de063b157692ef1241d6dd6b 100644
--- a/src/mol-base/collections/integer/segmentation.ts
+++ b/src/mol-base/collections/integer/segmentation.ts
@@ -13,6 +13,7 @@ namespace Segmentation {
     export interface Segment { index: number, start: number, end: number }
 
     export const create: (segs: ArrayLike<number>) => Segmentation = Impl.create as any;
+    export const ofOffsets: (offsets: ArrayLike<number>, bounds: Interval) => Segmentation = Impl.ofOffsets as any;
 
     export const count: (segs: Segmentation) => number = Impl.count as any;
     export const getSegment: (segs: Segmentation, value: number) => number = Impl.getSegment as any;
diff --git a/src/mol-base/collections/table.ts b/src/mol-base/collections/table.ts
index 087edc66b7f8f054432c0f24d7bc510fac41d6d0..fad8188538d32cdfdfa7faa03d4e76a55b23ca17 100644
--- a/src/mol-base/collections/table.ts
+++ b/src/mol-base/collections/table.ts
@@ -83,7 +83,7 @@ namespace Table {
         ret._rowCount = table._rowCount;
         ret._columns = table._columns;
         for (const c of table._columns) {
-            ret[c] = Column.permutation((table as any)[c], indices, false);
+            ret[c] = Column.view((table as any)[c], indices, false);
         }
         return ret;
     }
diff --git a/src/mol-data/model.ts b/src/mol-data/model.ts
index a9e450a0affa6b279eaccead06ddcc39de8eddb2..db02acf8aa71c13249c452eb500693b51834e39b 100644
--- a/src/mol-data/model.ts
+++ b/src/mol-data/model.ts
@@ -5,9 +5,8 @@
  */
 
 import * as Formats from './model/formats'
-//import CommonProperties from './model/properties/common'
-import MacromoleculeTree from './model/properties/macromolecule-tree'
-import Conformation from './model/properties/conformation'
+import MacromoleculeData from './model/data/macromolecule'
+import ConformationData from './model/data/conformation'
 import Segmentation from '../mol-base/collections/integer/segmentation'
 
 /**
@@ -22,9 +21,8 @@ interface Model extends Readonly<{
 
     sourceData: Formats.RawData,
 
-    //common: CommonProperties,
-    macromolecule: MacromoleculeTree,
-    conformation: Conformation,
+    macromolecule: MacromoleculeData,
+    conformation: ConformationData,
 
     // used for diffing.
     version: {
@@ -35,8 +33,7 @@ interface Model extends Readonly<{
     atomCount: number,
     segments: Readonly<{
         chains: Segmentation,
-        residues: Segmentation,
-        entities: Segmentation
+        residues: Segmentation
     }>
 }> { }
 
diff --git a/src/mol-data/model/builders/mmcif.ts b/src/mol-data/model/builders/mmcif.ts
index e9a26ff171bf7d642e9467c727124489d7a362e1..24ad91e491a3827f9c358bbfe431c9a73263029a 100644
--- a/src/mol-data/model/builders/mmcif.ts
+++ b/src/mol-data/model/builders/mmcif.ts
@@ -7,6 +7,7 @@
 import { RawData } from '../formats'
 import { Frame as mmCIF } from '../../../mol-io/reader/cif/schema/mmcif'
 import Model from '../../model'
+//import Column from '../../../mol-base/collections/column'
 import Interval from '../../../mol-base/collections/integer/interval'
 import Segmentation from '../../../mol-base/collections/integer/segmentation'
 import uuId from '../../../mol-base/utils/uuid'
@@ -20,40 +21,28 @@ function findModelBounds(data: mmCIF, startIndex: number) {
     return Interval.ofBounds(startIndex, endIndex);
 }
 
-function segment(data: mmCIF, bounds: Interval) {
+function segmentOffsets(data: mmCIF, bounds: Interval) {
     const start = Interval.start(bounds), end = Interval.end(bounds);
-    const residues = [0], chains = [0], entities = [0];
+    const residues = [start], chains = [start];
 
     const { label_entity_id, auth_asym_id, auth_seq_id, pdbx_PDB_ins_code, label_comp_id } = data.atom_site;
 
-    let offset = 1;
     for (let i = start + 1; i < end; i++) {
-        const newEntity = !label_entity_id.areValuesEqual(i - 1, i);
-        const newChain = newEntity || !auth_asym_id.areValuesEqual(i - 1, i);
+        const newChain = !label_entity_id.areValuesEqual(i - 1, i) || !auth_asym_id.areValuesEqual(i - 1, i);
         const newResidue = newChain
             || !auth_seq_id.areValuesEqual(i - 1, i)
             || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i)
             || !label_comp_id.areValuesEqual(i - 1, i);
 
-        if (newEntity) entities[entities.length] = offset;
-        if (newResidue) residues[residues.length] = offset;
-        if (newChain) chains[chains.length] = offset;
-        offset++;
+        if (newResidue) residues[residues.length] = i;
+        if (newChain) chains[chains.length] = i;
     }
 
-    residues[residues.length] = offset;
-    chains[chains.length] = offset;
-    entities[entities.length] = offset;
-
-    return {
-        residues: Segmentation.create(residues),
-        chains: Segmentation.create(chains),
-        entities: Segmentation.create(entities)
-    };
+    return { residues, chains };
 }
 
 function createModel(raw: RawData, data: mmCIF, bounds: Interval): Model {
-    const segments = segment(data, bounds);
+    const segments = segmentOffsets(data, bounds);
     return {
         id: uuId(),
         sourceData: raw,
@@ -63,7 +52,10 @@ function createModel(raw: RawData, data: mmCIF, bounds: Interval): Model {
         conformation: 0 as any,
         version: { data: 0, conformation: 0 },
         atomCount: Interval.size(bounds),
-        segments
+        segments: {
+            residues: Segmentation.ofOffsets(segments.residues, bounds),
+            chains: Segmentation.ofOffsets(segments.chains, bounds),
+        }
     };
 }
 
diff --git a/src/mol-data/model/properties/conformation.ts b/src/mol-data/model/data/conformation.ts
similarity index 100%
rename from src/mol-data/model/properties/conformation.ts
rename to src/mol-data/model/data/conformation.ts
diff --git a/src/mol-data/model/properties/macromolecule-tree.ts b/src/mol-data/model/data/macromolecule.ts
similarity index 100%
rename from src/mol-data/model/properties/macromolecule-tree.ts
rename to src/mol-data/model/data/macromolecule.ts
diff --git a/src/mol-data/model/properties/secondary-structure.ts b/src/mol-data/model/data/secondary-structure.ts
similarity index 100%
rename from src/mol-data/model/properties/secondary-structure.ts
rename to src/mol-data/model/data/secondary-structure.ts
diff --git a/src/mol-data/model/properties/transforms.ts b/src/mol-data/model/data/transforms.ts
similarity index 100%
rename from src/mol-data/model/properties/transforms.ts
rename to src/mol-data/model/data/transforms.ts
diff --git a/src/mol-io/reader/cif/data-model.ts b/src/mol-io/reader/cif/data-model.ts
index d353c534a9b4e573282cc8bf0dcf6b71bf7718a5..3d8c6edf42b20ebef5f940c392c81bab6792f92d 100644
--- a/src/mol-io/reader/cif/data-model.ts
+++ b/src/mol-io/reader/cif/data-model.ts
@@ -69,9 +69,9 @@ export interface Field {
 
     areValuesEqual(rowA: number, rowB: number): boolean,
 
-    toStringArray(params?: Column.ToArrayParams): ReadonlyArray<string>,
-    toIntArray(params?: Column.ToArrayParams): ReadonlyArray<number>,
-    toFloatArray(params?: Column.ToArrayParams): ReadonlyArray<number>
+    toStringArray(params?: Column.ToArrayParams<string>): ReadonlyArray<string>,
+    toIntArray(params?: Column.ToArrayParams<number>): ReadonlyArray<number>,
+    toFloatArray(params?: Column.ToArrayParams<number>): ReadonlyArray<number>
 }
 
 export function getMatrix(category: Category, field: string, rows: number, cols: number, row: number) {