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

data model part ? of ??

parent 1aa995df
No related branches found
No related tags found
No related merge requests found
Showing
with 64 additions and 56 deletions
...@@ -40,8 +40,9 @@ describe('column', () => { ...@@ -40,8 +40,9 @@ describe('column', () => {
expect(numStr.toArray()).toEqual(['1', '2']); expect(numStr.toArray()).toEqual(['1', '2']);
}); });
it('permutation', () => { it('view', () => {
expect(Column.permutation(arr, [1, 0, 3, 2]).toArray()).toEqual([2, 1, 4, 3]); 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', () => { it('map to array', () => {
......
...@@ -12,12 +12,13 @@ interface Column<T> { ...@@ -12,12 +12,13 @@ interface Column<T> {
readonly rowCount: number, readonly rowCount: number,
value(row: number): T, value(row: number): T,
valueKind(row: number): Column.ValueKind, valueKind(row: number): Column.ValueKind,
toArray(params?: Column.ToArrayParams): ReadonlyArray<T>, toArray(params?: Column.ToArrayParams<T>): ReadonlyArray<T>,
areValuesEqual(rowA: number, rowB: number): boolean areValuesEqual(rowA: number, rowB: number): boolean
} }
namespace Column { namespace Column {
export type Type<T = any> = Type.Str | Type.Int | Type.Float | Type.Vector | Type.Matrix | Type.Aliased<T> 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 namespace Type {
export type Str = { T: string, kind: 'str' } export type Str = { T: string, kind: 'str' }
...@@ -37,8 +38,8 @@ namespace Column { ...@@ -37,8 +38,8 @@ namespace Column {
export function aliased<T>(t: Type): Aliased<T> { return t as any as Aliased<T>; } export function aliased<T>(t: Type): Aliased<T> { return t as any as Aliased<T>; }
} }
export interface ToArrayParams { export interface ToArrayParams<T> {
array?: { new(size: number): ArrayLike<number> }, array?: ArrayCtor<T>,
start?: number, start?: number,
/** Last row (exclusive) */ /** Last row (exclusive) */
end?: number end?: number
...@@ -85,7 +86,7 @@ namespace Column { ...@@ -85,7 +86,7 @@ namespace Column {
return windowColumn(column, start, end); 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); return columnPermutation(column, indices, checkIndentity);
} }
...@@ -94,12 +95,12 @@ namespace Column { ...@@ -94,12 +95,12 @@ namespace Column {
return createFirstIndexMapOfColumn(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); return mapToArrayImpl(column, f, ctor || Array);
} }
/** Makes the column backned by an array. Useful for columns that accessed often. */ /** 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['@array']) return c;
if (!c.isDefined) return Undefined(c.rowCount, c['@type']) as any as Column<T>; 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 }); 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> { ...@@ -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++) { for (let i = 0, _i = map.length; i < _i; i++) {
if (map[i] !== i) return false; if (map[i] !== i) return false;
} }
...@@ -229,22 +231,22 @@ function isIdentity(map: ArrayLike<number>) { ...@@ -229,22 +231,22 @@ function isIdentity(map: ArrayLike<number>) {
function columnPermutation<T>(c: Column<T>, map: ArrayLike<number>, checkIdentity: boolean): Column<T> { function columnPermutation<T>(c: Column<T>, map: ArrayLike<number>, checkIdentity: boolean): Column<T> {
if (!c.isDefined) return c; if (!c.isDefined) return c;
if (checkIdentity && isIdentity(map)) return c; if (checkIdentity && isIdentity(map, c.rowCount)) return c;
if (!c['@array']) return permutationArray(c, map); if (!c['@array']) return arrayView(c, map);
return permutationFull(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 array = c['@array']!;
const ret = new (array as any).constructor(c.rowCount); const ret = new (array as any).constructor(map.length);
for (let i = 0, _i = c.rowCount; i < _i; i++) ret[i] = array[map[i]]; 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 }); 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 v = c.value, vk = c.valueKind, ave = c.areValuesEqual;
const value: Column<T>['value'] = row => v(map[row]); const value: Column<T>['value'] = row => v(map[row]);
const rowCount = c.rowCount; const rowCount = map.length;
return { return {
'@type': c['@type'], '@type': c['@type'],
'@array': void 0, '@array': void 0,
...@@ -261,20 +263,20 @@ function permutationFull<T>(c: Column<T>, map: ArrayLike<number>): Column<T> { ...@@ -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; const ret = new ctor(c.rowCount) as any;
for (let i = 0, _i = c.rowCount; i < _i; i++) ret[i] = f(c.value(i)); for (let i = 0, _i = c.rowCount; i < _i; i++) ret[i] = f(c.value(i));
return ret; return ret;
} }
export namespace ColumnHelpers { 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 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; const end = params && typeof params.end !== 'undefined' ? Math.min(params.end, rowCount) : rowCount;
return { start, end }; 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 c = params && typeof params.array !== 'undefined' ? params.array : Array;
const { start, end } = getArrayBounds(rowCount, params); const { start, end } = getArrayBounds(rowCount, params);
return { array: new c(end - start) as any[], start, end }; return { array: new c(end - start) as any[], start, end };
...@@ -285,7 +287,7 @@ export namespace ColumnHelpers { ...@@ -285,7 +287,7 @@ export namespace ColumnHelpers {
return target; 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); const { array, start } = createArray(rowCount, params);
return fillArrayValues(value, array, start); return fillArrayValues(value, array, start);
} }
...@@ -294,7 +296,7 @@ export namespace ColumnHelpers { ...@@ -294,7 +296,7 @@ export namespace ColumnHelpers {
return !!data.buffer && typeof data.byteLength === 'number' && typeof data.BYTES_PER_ELEMENT === 'number'; 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 { constructor, buffer, length, byteOffset, BYTES_PER_ELEMENT } = data;
const { start, end } = getArrayBounds(length, params); const { start, end } = getArrayBounds(length, params);
if (start === 0 && end === length) return data; if (start === 0 && end === length) return data;
......
...@@ -19,12 +19,17 @@ describe('segments', () => { ...@@ -19,12 +19,17 @@ describe('segments', () => {
expect(p).toBe(Interval.ofBounds(0, 2)) 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', () => { it('map', () => {
const segs = Segmentation.create([0, 1, 2]); const segs = Segmentation.create([0, 1, 2]);
expect(segs.segmentMap).toEqual(new Int32Array([0, 1])); expect(segs.segmentMap).toEqual(new Int32Array([0, 1]));
expect(Segmentation.getSegment(segs, 0)).toBe(0); expect(Segmentation.getSegment(segs, 0)).toBe(0);
expect(Segmentation.getSegment(segs, 1)).toBe(1); expect(Segmentation.getSegment(segs, 1)).toBe(1);
}) });
it('iteration', () => { it('iteration', () => {
const it = Segmentation.transientSegments(segs, data); const it = Segmentation.transientSegments(segs, data);
......
...@@ -10,7 +10,7 @@ import Interval from '../interval' ...@@ -10,7 +10,7 @@ import Interval from '../interval'
import SortedArray from '../sorted-array' import SortedArray from '../sorted-array'
import Segs from '../segmentation' 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 { export function create(values: ArrayLike<number>): Segmentation {
const segments = SortedArray.ofSortedArray(values); const segments = SortedArray.ofSortedArray(values);
...@@ -24,6 +24,16 @@ export function create(values: ArrayLike<number>): Segmentation { ...@@ -24,6 +24,16 @@ export function create(values: ArrayLike<number>): Segmentation {
return { segments, segmentMap, count: values.length - 1 }; 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 count({ count }: Segmentation) { return count; }
export function getSegment({ segmentMap }: Segmentation, value: number) { return segmentMap[value]; } export function getSegment({ segmentMap }: Segmentation, value: number) { return segmentMap[value]; }
......
...@@ -13,6 +13,7 @@ namespace Segmentation { ...@@ -13,6 +13,7 @@ namespace Segmentation {
export interface Segment { index: number, start: number, end: number } export interface Segment { index: number, start: number, end: number }
export const create: (segs: ArrayLike<number>) => Segmentation = Impl.create as any; 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 count: (segs: Segmentation) => number = Impl.count as any;
export const getSegment: (segs: Segmentation, value: number) => number = Impl.getSegment as any; export const getSegment: (segs: Segmentation, value: number) => number = Impl.getSegment as any;
......
...@@ -83,7 +83,7 @@ namespace Table { ...@@ -83,7 +83,7 @@ namespace Table {
ret._rowCount = table._rowCount; ret._rowCount = table._rowCount;
ret._columns = table._columns; ret._columns = table._columns;
for (const c of 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; return ret;
} }
......
...@@ -5,9 +5,8 @@ ...@@ -5,9 +5,8 @@
*/ */
import * as Formats from './model/formats' import * as Formats from './model/formats'
//import CommonProperties from './model/properties/common' import MacromoleculeData from './model/data/macromolecule'
import MacromoleculeTree from './model/properties/macromolecule-tree' import ConformationData from './model/data/conformation'
import Conformation from './model/properties/conformation'
import Segmentation from '../mol-base/collections/integer/segmentation' import Segmentation from '../mol-base/collections/integer/segmentation'
/** /**
...@@ -22,9 +21,8 @@ interface Model extends Readonly<{ ...@@ -22,9 +21,8 @@ interface Model extends Readonly<{
sourceData: Formats.RawData, sourceData: Formats.RawData,
//common: CommonProperties, macromolecule: MacromoleculeData,
macromolecule: MacromoleculeTree, conformation: ConformationData,
conformation: Conformation,
// used for diffing. // used for diffing.
version: { version: {
...@@ -35,8 +33,7 @@ interface Model extends Readonly<{ ...@@ -35,8 +33,7 @@ interface Model extends Readonly<{
atomCount: number, atomCount: number,
segments: Readonly<{ segments: Readonly<{
chains: Segmentation, chains: Segmentation,
residues: Segmentation, residues: Segmentation
entities: Segmentation
}> }>
}> { } }> { }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import { RawData } from '../formats' import { RawData } from '../formats'
import { Frame as mmCIF } from '../../../mol-io/reader/cif/schema/mmcif' import { Frame as mmCIF } from '../../../mol-io/reader/cif/schema/mmcif'
import Model from '../../model' import Model from '../../model'
//import Column from '../../../mol-base/collections/column'
import Interval from '../../../mol-base/collections/integer/interval' import Interval from '../../../mol-base/collections/integer/interval'
import Segmentation from '../../../mol-base/collections/integer/segmentation' import Segmentation from '../../../mol-base/collections/integer/segmentation'
import uuId from '../../../mol-base/utils/uuid' import uuId from '../../../mol-base/utils/uuid'
...@@ -20,40 +21,28 @@ function findModelBounds(data: mmCIF, startIndex: number) { ...@@ -20,40 +21,28 @@ function findModelBounds(data: mmCIF, startIndex: number) {
return Interval.ofBounds(startIndex, endIndex); 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 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; 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++) { for (let i = start + 1; i < end; i++) {
const newEntity = !label_entity_id.areValuesEqual(i - 1, i); const newChain = !label_entity_id.areValuesEqual(i - 1, i) || !auth_asym_id.areValuesEqual(i - 1, i);
const newChain = newEntity || !auth_asym_id.areValuesEqual(i - 1, i);
const newResidue = newChain const newResidue = newChain
|| !auth_seq_id.areValuesEqual(i - 1, i) || !auth_seq_id.areValuesEqual(i - 1, i)
|| !pdbx_PDB_ins_code.areValuesEqual(i - 1, i) || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i)
|| !label_comp_id.areValuesEqual(i - 1, i); || !label_comp_id.areValuesEqual(i - 1, i);
if (newEntity) entities[entities.length] = offset; if (newResidue) residues[residues.length] = i;
if (newResidue) residues[residues.length] = offset; if (newChain) chains[chains.length] = i;
if (newChain) chains[chains.length] = offset;
offset++;
} }
residues[residues.length] = offset; return { residues, chains };
chains[chains.length] = offset;
entities[entities.length] = offset;
return {
residues: Segmentation.create(residues),
chains: Segmentation.create(chains),
entities: Segmentation.create(entities)
};
} }
function createModel(raw: RawData, data: mmCIF, bounds: Interval): Model { function createModel(raw: RawData, data: mmCIF, bounds: Interval): Model {
const segments = segment(data, bounds); const segments = segmentOffsets(data, bounds);
return { return {
id: uuId(), id: uuId(),
sourceData: raw, sourceData: raw,
...@@ -63,7 +52,10 @@ function createModel(raw: RawData, data: mmCIF, bounds: Interval): Model { ...@@ -63,7 +52,10 @@ function createModel(raw: RawData, data: mmCIF, bounds: Interval): Model {
conformation: 0 as any, conformation: 0 as any,
version: { data: 0, conformation: 0 }, version: { data: 0, conformation: 0 },
atomCount: Interval.size(bounds), atomCount: Interval.size(bounds),
segments segments: {
residues: Segmentation.ofOffsets(segments.residues, bounds),
chains: Segmentation.ofOffsets(segments.chains, bounds),
}
}; };
} }
......
...@@ -69,9 +69,9 @@ export interface Field { ...@@ -69,9 +69,9 @@ export interface Field {
areValuesEqual(rowA: number, rowB: number): boolean, areValuesEqual(rowA: number, rowB: number): boolean,
toStringArray(params?: Column.ToArrayParams): ReadonlyArray<string>, toStringArray(params?: Column.ToArrayParams<string>): ReadonlyArray<string>,
toIntArray(params?: Column.ToArrayParams): ReadonlyArray<number>, toIntArray(params?: Column.ToArrayParams<number>): ReadonlyArray<number>,
toFloatArray(params?: Column.ToArrayParams): ReadonlyArray<number> toFloatArray(params?: Column.ToArrayParams<number>): ReadonlyArray<number>
} }
export function getMatrix(category: Category, field: string, rows: number, cols: number, row: number) { export function getMatrix(category: Category, field: string, rows: number, cols: number, row: number) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment