diff --git a/src/mol-data/int/impl/sorted-array.ts b/src/mol-data/int/impl/sorted-array.ts index f3147c7086664c7900c78db8c89f1e87b15ff509..11a964b172a1a61070e24298af22d747150f9ff4 100644 --- a/src/mol-data/int/impl/sorted-array.ts +++ b/src/mol-data/int/impl/sorted-array.ts @@ -15,6 +15,12 @@ export const Empty: Nums = [] export function ofSingleton(v: number) { return [v]; } export function ofSortedArray(xs: Nums) { return xs; } export function ofUnsortedArray(xs: Nums) { sortArray(xs); return xs; } +export function ofRange(min: number, max: number) { + if (max < min) return []; + const ret = new Int32Array(max - min + 1); + for (let i = min; i <= max; i++) ret[i - min] = i; + return ret; +} export function is(xs: any): xs is Nums { return xs && (Array.isArray(xs) || !!xs.buffer); } export function start(xs: Nums) { return xs[0]; } diff --git a/src/mol-data/int/sorted-array.ts b/src/mol-data/int/sorted-array.ts index 08235061224bfebfdf5f019281936e5c090bb65b..2b8391cb5cf929a7f45aa7e05da7b83f242431d1 100644 --- a/src/mol-data/int/sorted-array.ts +++ b/src/mol-data/int/sorted-array.ts @@ -12,6 +12,10 @@ namespace SortedArray { export const ofUnsortedArray: (xs: ArrayLike<number>) => SortedArray = Impl.ofUnsortedArray as any; export const ofSingleton: (v: number) => SortedArray = Impl.ofSingleton as any; export const ofSortedArray: (xs: ArrayLike<number>) => SortedArray = Impl.ofSortedArray as any; + // create sorted array [min, max] (it DOES contain the max value) + export const ofRange: (min: number, max: number) => SortedArray = Impl.ofRange as any; + // create sorted array [min, max) (it DOES not contain the max value) + export const ofBounds: (min: number, max: number) => SortedArray = (min, max) => Impl.ofRange(min, max - 1) as any; export const is: (v: any) => v is Interval = Impl.is as any; export const has: (array: SortedArray, x: number) => boolean = Impl.has as any; diff --git a/src/mol-data/util/sort.ts b/src/mol-data/util/sort.ts index e6eb6571ea82387a9e121e364ecb6528847d7da9..8068a449124aeb9d2b6dac403e0a4ba810fa8e2a 100644 --- a/src/mol-data/util/sort.ts +++ b/src/mol-data/util/sort.ts @@ -13,10 +13,10 @@ export function arrayLess(arr: ArrayLike<number>, i: number, j: number) { return arr[i] - arr[j]; } -export function arraySwap(arr: any[], i: number, j: number) { +export function arraySwap(arr: ArrayLike<any>, i: number, j: number) { const temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; + (arr as any[])[i] = arr[j]; + (arr as any[])[j] = temp; } function medianPivotIndex(data: any, cmp: Comparer, l: number, r: number) { diff --git a/src/mol-math/geometry/symmetry-operator.ts b/src/mol-math/geometry/symmetry-operator.ts index 6b65fafd045d6bd31dcfbe1b2eb59308b44a37be..fe6cbc7aa04ca0deaa8869cb4afbe7998fc7669e 100644 --- a/src/mol-math/geometry/symmetry-operator.ts +++ b/src/mol-math/geometry/symmetry-operator.ts @@ -48,11 +48,11 @@ namespace SymmetryOperator { export interface Coordinates { x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number> } - export function createMapping(operator: SymmetryOperator, coords: Coordinates) { + export function createMapping(operator: SymmetryOperator, coords: Coordinates): ArrayMapping { const invariantPosition = SymmetryOperator.createCoordinateMapper(SymmetryOperator.Default, coords); const position = operator.isIdentity ? invariantPosition : SymmetryOperator.createCoordinateMapper(operator, coords); const { x, y, z } = createProjections(operator, coords); - return { invariantPosition, position, x, y, z }; + return { operator, invariantPosition, position, x, y, z }; } export function createCoordinateMapper(t: SymmetryOperator, coords: Coordinates): CoordinateMapper { diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index 3958a39faf09c85e7d07a2daca46530a396674df..65ded0cbbcb3c48f51824ca0649699f9c3f350e7 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -9,7 +9,7 @@ import { Column } from 'mol-data/db' import Iterator from 'mol-data/iterator' import * as Encoder from 'mol-io/writer/cif' // import { mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif' -import { Structure, Element, ElementSet } from '../structure' +import { Structure, Element } from '../structure' import { Model } from '../model' import P from '../query/properties' @@ -113,8 +113,8 @@ function atomSiteProvider({ structure }: Context): Encoder.CategoryInstance { return { data: void 0, definition: atom_site, - keys: () => Structure.elementLocationsTransient(structure), - rowCount: ElementSet.elementCount(structure.elements) + keys: () => structure.elementLocations(), + rowCount: structure.elementCount } } diff --git a/src/mol-model/structure/query/generators.ts b/src/mol-model/structure/query/generators.ts index 66c9f0415dd28f02c0f2ad74eac035ec09d305eb..c97533b54e0b03f1df9917eb0aaaf4ca0feda9d5 100644 --- a/src/mol-model/structure/query/generators.ts +++ b/src/mol-model/structure/query/generators.ts @@ -7,10 +7,10 @@ import Query from './query' import Selection from './selection' import P from './properties' -import { Structure, ElementSet, Element, Unit } from '../structure' +import { Structure, Element, Unit } from '../structure' import { OrderedSet, Segmentation } from 'mol-data/int' -export const all: Query.Provider = async (s, ctx) => Selection.Singletons(s, s.elements); +export const all: Query.Provider = async (s, ctx) => Selection.Singletons(s, s); export interface AtomQueryParams { entityTest: Element.Predicate, @@ -45,90 +45,86 @@ export function atoms(params?: Partial<AtomGroupsQueryParams>): Query.Provider { function atomGroupsLinear(atomTest: Element.Predicate): Query.Provider { return async (structure, ctx) => { - const { elements, units } = structure; - const unitIds = ElementSet.unitIndices(elements); + const { units } = structure; const l = Element.Location(); - const builder = ElementSet.LinearBuilder(elements); + const builder = structure.subsetBuilder(true); - for (let i = 0, _i = unitIds.length; i < _i; i++) { - const unitId = unitIds[i]; - l.unit = units[unitId]; - const set = ElementSet.groupAt(elements, i).elements; + for (const unit of units) { + l.unit = unit; + const elements = unit.elements; - builder.beginUnit(); - for (let j = 0, _j = OrderedSet.size(set); j < _j; j++) { - l.element = OrderedSet.getAt(set, j); - if (atomTest(l)) builder.addToUnit(l.element); + builder.beginUnit(unit.id); + for (let j = 0, _j = elements.length; j < _j; j++) { + l.element = elements[j]; + if (atomTest(l)) builder.addElement(l.element); } - builder.commitUnit(unitId); + builder.commitUnit(); - if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: unitIds.length }); + if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: units.length }); } - return Selection.Singletons(structure, builder.getSet()); + return Selection.Singletons(structure, builder.getStructure()); }; } function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomGroupsQueryParams): Query.Provider { return async (structure, ctx) => { - const { elements, units } = structure; - const unitIds = ElementSet.unitIndices(elements); + const { units } = structure; const l = Element.Location(); - const builder = ElementSet.LinearBuilder(elements); - - for (let i = 0, _i = unitIds.length; i < _i; i++) { - const unitId = unitIds[i]; - const unit = units[unitId]; + const builder = structure.subsetBuilder(true); + for (const unit of units) { if (unit.kind !== Unit.Kind.Atomic) continue; l.unit = unit; - const set = ElementSet.groupAt(elements, i).elements; + const elements = unit.elements; - builder.beginUnit(); - const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set); - const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set); + builder.beginUnit(unit.id); + const chainsIt = Segmentation.transientSegments(unit.model.hierarchy.chainSegments, elements); + const residuesIt = Segmentation.transientSegments(unit.model.hierarchy.residueSegments, elements); while (chainsIt.hasNext) { const chainSegment = chainsIt.move(); - l.element = OrderedSet.getAt(set, chainSegment.start); + l.element = OrderedSet.getAt(elements, chainSegment.start); // test entity and chain if (!entityTest(l) || !chainTest(l)) continue; residuesIt.setSegment(chainSegment); while (residuesIt.hasNext) { const residueSegment = residuesIt.move(); - l.element = OrderedSet.getAt(set, residueSegment.start); + l.element = OrderedSet.getAt(elements, residueSegment.start); // test residue if (!residueTest(l)) continue; for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { - l.element = OrderedSet.getAt(set, j); - if (atomTest(l)) builder.addToUnit(l.element); + l.element = OrderedSet.getAt(elements, j); + if (atomTest(l)) { + builder.addElement(l.element); + } } } } - builder.commitUnit(unitId); + builder.commitUnit(); - if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: unitIds.length }); + if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: units.length }); } - return Selection.Singletons(structure, builder.getSet()); + return Selection.Singletons(structure, builder.getStructure()); }; } class LinearGroupingBuilder { - private builders: ElementSet.Builder[] = []; - private builderMap = new Map<string, ElementSet.Builder>(); + private builders: Structure.SubsetBuilder[] = []; + private builderMap = new Map<string, Structure.SubsetBuilder>(); - add(key: any, unit: number, atom: number) { + add(key: any, unit: number, element: number) { let b = this.builderMap.get(key); if (!b) { - b = ElementSet.LinearBuilder(this.structure.elements); + b = this.source.subsetBuilder(true); this.builders[this.builders.length] = b; this.builderMap.set(key, b); } - b.add(unit, atom); + b.addToUnit(unit, element); } private allSingletons() { @@ -139,71 +135,68 @@ class LinearGroupingBuilder { } private singletonSelection(): Selection { - const atoms: Element[] = Element.createEmptyArray(this.builders.length); + const builder = this.source.subsetBuilder(true); for (let i = 0, _i = this.builders.length; i < _i; i++) { - atoms[i] = this.builders[i].singleton(); + const e = this.builders[i].singleton(); + builder.addToUnit(Element.unit(e), Element.index(e)); } - return Selection.Singletons(this.structure, ElementSet.ofAtoms(atoms, this.structure.elements)); + return Selection.Singletons(this.source, builder.getStructure()); } private fullSelection() { - const sets: ElementSet[] = new Array(this.builders.length); + const structures: Structure[] = new Array(this.builders.length); for (let i = 0, _i = this.builders.length; i < _i; i++) { - sets[i] = this.builders[i].getSet(); + structures[i] = this.builders[i].getStructure(); } - return Selection.Sequence(this.structure, sets); + return Selection.Sequence(this.source, structures); } getSelection(): Selection { const len = this.builders.length; - if (len === 0) return Selection.Empty(this.structure); + if (len === 0) return Selection.Empty(this.source); if (this.allSingletons()) return this.singletonSelection(); return this.fullSelection(); } - constructor(private structure: Structure) { } + constructor(private source: Structure) { } } function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomGroupsQueryParams): Query.Provider { return async (structure, ctx) => { - const { elements, units } = structure; - const unitIds = ElementSet.unitIndices(elements); + const { units } = structure; const l = Element.Location(); const builder = new LinearGroupingBuilder(structure); - for (let i = 0, _i = unitIds.length; i < _i; i++) { - const unitId = unitIds[i]; - const unit = units[unitId]; - + for (const unit of units) { if (unit.kind !== Unit.Kind.Atomic) continue; l.unit = unit; - const set = ElementSet.groupAt(elements, i).elements; + const elements = unit.elements; - const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set); - const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set); + const chainsIt = Segmentation.transientSegments(unit.model.hierarchy.chainSegments, elements); + const residuesIt = Segmentation.transientSegments(unit.model.hierarchy.residueSegments, elements); while (chainsIt.hasNext) { const chainSegment = chainsIt.move(); - l.element = OrderedSet.getAt(set, chainSegment.start); + l.element = OrderedSet.getAt(elements, chainSegment.start); // test entity and chain if (!entityTest(l) || !chainTest(l)) continue; residuesIt.setSegment(chainSegment); while (residuesIt.hasNext) { const residueSegment = residuesIt.move(); - l.element = OrderedSet.getAt(set, residueSegment.start); + l.element = OrderedSet.getAt(elements, residueSegment.start); // test residue if (!residueTest(l)) continue; for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { - l.element = OrderedSet.getAt(set, j); - if (atomTest(l)) builder.add(groupBy(l), unitId, l.element); + l.element = OrderedSet.getAt(elements, j); + if (atomTest(l)) builder.add(groupBy(l), unit.id, l.element); } } } - if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: unitIds.length }); + if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: units.length }); } return builder.getSelection(); diff --git a/src/mol-model/structure/query/properties.ts b/src/mol-model/structure/query/properties.ts index 1381966083177d1216ba3603561979fbb20d1453..fc2a066ad957730fe49ec9a884ffb47a822156e6 100644 --- a/src/mol-model/structure/query/properties.ts +++ b/src/mol-model/structure/query/properties.ts @@ -26,41 +26,41 @@ const atom = { key: Element.property(l => l.element), // Conformation - 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)), + x: Element.property(l => l.unit.conformation.x(l.element)), + y: Element.property(l => l.unit.conformation.y(l.element)), + z: Element.property(l => l.unit.conformation.z(l.element)), + id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomSiteConformation.atomId.value(l.element)), + occupancy: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomSiteConformation.occupancy.value(l.element)), + B_iso_or_equiv: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomSiteConformation.B_iso_or_equiv.value(l.element)), // Hierarchy - type_symbol: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.atoms.type_symbol.value(l.element)), - label_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.atoms.label_atom_id.value(l.element)), - auth_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.atoms.auth_atom_id.value(l.element)), - label_alt_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.atoms.label_alt_id.value(l.element)), - pdbx_formal_charge: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.atoms.pdbx_formal_charge.value(l.element)), + type_symbol: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.type_symbol.value(l.element)), + label_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.label_atom_id.value(l.element)), + auth_atom_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.auth_atom_id.value(l.element)), + label_alt_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.label_alt_id.value(l.element)), + pdbx_formal_charge: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.atoms.pdbx_formal_charge.value(l.element)), // Derived - vdw_radius: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : VdwRadius(l.unit.hierarchy.atoms.type_symbol.value(l.element))), + vdw_radius: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : VdwRadius(l.unit.model.hierarchy.atoms.type_symbol.value(l.element))), } const residue = { - 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])) + key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residueKey.value(l.unit.residueIndex[l.element])), + + group_PDB: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.group_PDB.value(l.unit.residueIndex[l.element])), + label_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.label_comp_id.value(l.unit.residueIndex[l.element])), + auth_comp_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.auth_comp_id.value(l.unit.residueIndex[l.element])), + label_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.residues.label_seq_id.value(l.unit.residueIndex[l.element])), + auth_seq_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.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.model.hierarchy.residues.pdbx_PDB_ins_code.value(l.unit.residueIndex[l.element])) } const chain = { - key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chainKey.value(l.unit.chainIndex[l.element])), + key: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chainKey.value(l.unit.chainIndex[l.element])), - 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])) + label_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chains.label_asym_id.value(l.unit.chainIndex[l.element])), + auth_asym_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chains.auth_asym_id.value(l.unit.chainIndex[l.element])), + label_entity_id: Element.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.chains.label_entity_id.value(l.unit.chainIndex[l.element])) } const coarse_grained = { @@ -83,7 +83,7 @@ const coarse_grained = { gaussian_covariance_matrix: Element.property(l => !Unit.isGaussians(l.unit) ? notCoarse('gaussians') : l.unit.sites.covariance_matrix.value(l.element)) } -function eK(l: Element.Location) { return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.entityKey.value(l.unit.chainIndex[l.element]); } +function eK(l: Element.Location) { return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.hierarchy.entityKey.value(l.unit.chainIndex[l.element]); } const entity = { key: eK, @@ -101,7 +101,7 @@ const entity = { } const unit = { - operator_name: Element.property(l => l.unit.operator.name), + operator_name: Element.property(l => l.unit.conformation.operator.name), model_num: Element.property(l => l.unit.model.modelNum) } diff --git a/src/mol-model/structure/query/selection.ts b/src/mol-model/structure/query/selection.ts index f9f516710817ea7ae9d8c042457a7f81e2f53a2d..02235ee8eeb147c52b50f7ed385eb60504f67e37 100644 --- a/src/mol-model/structure/query/selection.ts +++ b/src/mol-model/structure/query/selection.ts @@ -5,102 +5,76 @@ */ import { HashSet } from 'mol-data/generic' -import { Structure, ElementSet } from '../structure' +import { Structure } from '../structure' +import { SortedArray } from 'mol-data/int'; // A selection is a pair of a Structure and a sequence of unique AtomSets type Selection = Selection.Singletons | Selection.Sequence namespace 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: ElementSet } - export interface Sequence { readonly kind: 'sequence', readonly structure: Structure, readonly sets: ReadonlyArray<ElementSet> } + export interface Singletons { readonly kind: 'singletons', readonly source: Structure, readonly structure: Structure } + export interface Sequence { readonly kind: 'sequence', readonly source: Structure, readonly structures: Structure[] } - 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 Singletons(source: Structure, structure: Structure): Singletons { return { kind: 'singletons', source, structure } } + export function Sequence(source: Structure, structures: Structure[]): Sequence { return { kind: 'sequence', source, structures } } + export function Empty(source: Structure): Selection { return Singletons(source, Structure.Empty); }; export function isSingleton(s: Selection): s is Singletons { return s.kind === 'singletons'; } - export function isEmpty(s: Selection) { return isSingleton(s) ? ElementSet.elementCount(s.set) === 0 : s.sets.length === 0; } + export function isEmpty(s: Selection) { return isSingleton(s) ? s.structure.units.length === 0 : s.structures.length === 0; } export function structureCount(sel: Selection) { - if (isSingleton(sel)) return ElementSet.elementCount(sel.set); - return sel.sets.length; + if (isSingleton(sel)) return sel.structure.elementCount; + return sel.structures.length; } 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, ElementSet.union(sel.sets, sel.structure.elements)); - } - - export function getAt(sel: Selection, i: number): Structure { - if (isSingleton(sel)) { - const atom = ElementSet.elementAt(sel.set, i); - return Structure.create(sel.structure.units, ElementSet.singleton(atom, sel.structure.elements)); - } - return Structure.create(sel.structure.units, sel.sets[i]); - } - - export function toStructures(sel: Selection): Structure[] { - const { units } = sel.structure; - if (isSingleton(sel)) { - const ret: Structure[] = new Array(ElementSet.elementCount(sel.set)); - const atoms = ElementSet.elements(sel.set); - let offset = 0; - while (atoms.hasNext) { - const atom = atoms.move(); - ret[offset++] = Structure.create(units, ElementSet.singleton(atom, sel.structure.elements)) - } - return ret; - } else { - const { sets } = sel; - const ret: Structure[] = new Array(sets.length); - for (let i = 0, _i = sets.length; i < _i; i++) ret[i] = Structure.create(units, sets[i]); - return ret; - } + if (isEmpty(sel)) return Structure.Empty; + if (isSingleton(sel)) return sel.structure; + return union(sel.source, sel.structures); } export interface Builder { - add(set: ElementSet): void, + add(structure: Structure): void, getSelection(): Selection } - function getSelection(structure: Structure, sets: ElementSet[], allSingletons: boolean) { - const len = sets.length; - if (len === 0) return Empty(structure); - if (allSingletons) return Singletons(structure, ElementSet.union(sets, structure.elements)); - return Sequence(structure, sets); + function getSelection(source: Structure, structures: Structure[], allSingletons: boolean) { + const len = structures.length; + if (len === 0) return Empty(source); + if (allSingletons) return Singletons(source, union(source, structures)); + return Sequence(source, structures); } class LinearBuilderImpl implements Builder { - private sets: ElementSet[] = []; + private structures: Structure[] = []; private allSingletons = true; - add(atoms: ElementSet) { - const atomCount = ElementSet.elementCount(atoms); - if (atomCount === 0) return; - this.sets[this.sets.length] = atoms; - if (atomCount !== 1) this.allSingletons = false; + add(structure: Structure) { + const elementCount = structure.elementCount; + if (elementCount === 0) return; + this.structures[this.structures.length] = structure; + if (elementCount !== 1) this.allSingletons = false; } - getSelection() { return getSelection(this.structure, this.sets, this.allSingletons); } + getSelection() { return getSelection(this.source, this.structures, this.allSingletons); } - constructor(private structure: Structure) { } + constructor(private source: Structure) { } } class HashBuilderImpl implements Builder { - private sets: ElementSet[] = []; + private structures: Structure[] = []; private allSingletons = true; - private uniqueSets = HashSet(ElementSet.hashCode, ElementSet.areEqual); + private uniqueSets = HashSet(Structure.hashCode, Structure.areEqual); - add(atoms: ElementSet) { - const atomCount = ElementSet.elementCount(atoms); - if (atomCount === 0 || !this.uniqueSets.add(atoms)) return; - this.sets[this.sets.length] = atoms; + add(structure: Structure) { + const atomCount = structure.elementCount; + if (atomCount === 0 || !this.uniqueSets.add(structure)) return; + this.structures[this.structures.length] = structure; if (atomCount !== 1) this.allSingletons = false; } - getSelection() { return getSelection(this.structure, this.sets, this.allSingletons); } + getSelection() { return getSelection(this.structure, this.structures, this.allSingletons); } constructor(private structure: Structure) { } } @@ -109,6 +83,38 @@ namespace Selection { export function UniqueBuilder(structure: Structure): Builder { return new HashBuilderImpl(structure); } // TODO: spatial lookup + + function union(source: Structure, structures: Structure[]) { + if (structures.length === 0) return Structure.Empty; + if (structures.length === 1) return structures[0]; + + const unitMap = new Map<number, SortedArray>(); + const fullUnits = new Set<number>(); + + for (const { units } of structures) { + for (let i = 0, _i = units.length; i < _i; i++) { + const u = units[i]; + if (unitMap.has(u.id)) { + // check if there is anything more to union in this particual unit. + if (fullUnits.has(u.id)) continue; + const merged = SortedArray.union(unitMap.get(u.id)!, u.elements); + unitMap.set(u.id, merged); + if (merged.length === source.unitMap.get(u.id).elements.length) fullUnits.add(u.id); + } else { + unitMap.set(u.id, u.elements); + if (u.elements.length === source.unitMap.get(u.id).elements.length) fullUnits.add(u.id); + } + } + } + + const builder = source.subsetBuilder(true); + unitMap.forEach(buildUnion, builder); + return builder.getStructure(); + } + + function buildUnion(this: Structure.SubsetBuilder, elements: SortedArray, id: number) { + this.setUnit(id, elements); + } } export default Selection \ No newline at end of file diff --git a/src/mol-model/structure/structure.ts b/src/mol-model/structure/structure.ts index 59f200b700ccd406f08a897a847e84b60acc7bee..0a3826b643d288bcd12f81ef695a288a68b07f5a 100644 --- a/src/mol-model/structure/structure.ts +++ b/src/mol-model/structure/structure.ts @@ -5,10 +5,8 @@ */ import Element from './structure/element' -import ElementSet from './structure/element/set' -import ElementGroup from './structure/element/group' import Structure from './structure/structure' import Unit from './structure/unit' import Symmetry from './structure/symmetry' -export { Element, ElementSet, ElementGroup, Structure, Unit, Symmetry } \ No newline at end of file +export { Element, Structure, Unit, Symmetry } \ No newline at end of file diff --git a/src/mol-model/structure/structure/element/group.ts b/src/mol-model/structure/structure/element/group.ts index e89b3d37e87b6611a0630fe4978fe1218ceaa76b..04c4e12ac140962f559d46478e8313e287b102c8 100644 --- a/src/mol-model/structure/structure/element/group.ts +++ b/src/mol-model/structure/structure/element/group.ts @@ -30,7 +30,7 @@ namespace ElementGroup { } export function create(unit: Unit, elements: OrderedSet): ElementGroup { - if (OrderedSet.areEqual(elements, unit.fullGroup.elements)) return unit.fullGroup; + //if (OrderedSet.areEqual(elements, unit.fullGroup.elements)) return unit.fullGroup; return createNew(elements); } diff --git a/src/mol-model/structure/structure/element/impl/set.ts b/src/mol-model/structure/structure/element/impl/set.ts index 2aaf3182e5f1ea62f0c313357d3b48d6b8a5dd4c..17ada0b577a782c9699697a31b01764f10396c14 100644 --- a/src/mol-model/structure/structure/element/impl/set.ts +++ b/src/mol-model/structure/structure/element/impl/set.ts @@ -9,18 +9,13 @@ import { sortArray } from 'mol-data/util/sort' import { hash1 } from 'mol-data/util/hash-functions' import Element from '../../element' import ElementGroup from '../group' -import { ElementSetLookup3D } from '../../util/lookup3d' -import Structure from '../../structure'; - /** Long and painful implementation starts here */ export type ElementSetImpl = { groups: IntMap<ElementGroup>, offsets: Int32Array, hashCode: number, - keys: SortedArray, - - __lookup3d__?: ElementSetLookup3D + keys: SortedArray } export const Empty: ElementSetImpl = { groups: IntMap.Empty, offsets: new Int32Array(1), hashCode: 0, keys: SortedArray.Empty }; @@ -279,13 +274,6 @@ export function Generator() { return new AtomSetGenerator(); } -export function getLookup3d(s: Structure) { - const set = s.elements as any as ElementSetImpl; - if (set.__lookup3d__) return set.__lookup3d__; - set.__lookup3d__ = ElementSetLookup3D.create(s); - return set.__lookup3d__; -} - /** When adding groups, compare them to existing ones. If they all match, return the whole original set. */ class ChildGenerator { private keys: number[] = []; diff --git a/src/mol-model/structure/structure/element/set.ts b/src/mol-model/structure/structure/element/set.ts index dddebe8bfd28b73505e0c93d18840a68087d83d4..0482f2d9edd3a38964eca9092a48131c2ec8daeb 100644 --- a/src/mol-model/structure/structure/element/set.ts +++ b/src/mol-model/structure/structure/element/set.ts @@ -9,7 +9,7 @@ import Element from '../element' import ElementGroup from './group' import * as Impl from './impl/set' import * as Builders from './impl/set-builder' -import { ElementSetLookup3D } from '../util/lookup3d'; +import { StructureLookup3D } from '../util/lookup3d'; import Structure from '../structure'; /** @@ -55,8 +55,6 @@ namespace ElementSet { export interface TemplateGenerator { add(unit: number, set: OrderedSet): void, getSet(): ElementSet } export const TemplateGenerator: (template: ElementSet) => TemplateGenerator = Impl.TemplateGenerator as any - export const getLookup3d: (s: Structure) => ElementSetLookup3D = Impl.getLookup3d; - // TODO: distance, areWithIn? // TODO: check connected // TODO: add "parent" property? how to avoid using too much memory? Transitive parents? Parent unlinking? diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 4447c1936c1b78c89043b000403207434cde3a3c..c3df4747734b34827515145a7ec48d6c8566702d 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -4,25 +4,75 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { OrderedSet, Iterator } from 'mol-data/int' +import { IntMap, SortedArray, Iterator } from 'mol-data/int' import { UniqueArray } from 'mol-data/generic' import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator' import { Model, Format } from '../model' -import Unit from './unit' -import ElementSet from './element/set' -import ElementGroup from './element/group' +import { sortArray, sort, arraySwap, hash1 } from 'mol-data/util'; import Element from './element' +import Unit from './unit' +import { StructureLookup3D } from './util/lookup3d'; // A structure is a pair of "units" and an element set. // Each unit contains the data and transformation of its corresponding elements. -interface Structure { - readonly units: ReadonlyArray<Unit>, - readonly elements: ElementSet +class Structure { + readonly unitMap: IntMap<Unit>; + readonly units: ReadonlyArray<Unit>; + readonly elementCount: number; + + private _hashCode = 0; + + subsetBuilder(isSorted: boolean) { + return new Structure.SubsetBuilder(this, isSorted); + } + + get hashCode() { + if (this._hashCode !== 0) return this._hashCode; + return this.computeHash(); + } + + private computeHash() { + let hash = 23; + for (let i = 0, _i = this.units.length; i < _i; i++) { + const u = this.units[i]; + hash = (31 * hash + u.id) | 0; + hash = (31 * hash + SortedArray.hashCode(u.elements)) | 0; + } + hash = (31 * hash + this.elementCount) | 0; + hash = hash1(hash); + this._hashCode = hash; + return hash; + } + + elementLocations(): Iterator<Element.Location> { + return new Structure.ElementLocationIterator(this); + } + + constructor(units: ArrayLike<Unit>) { + const map = IntMap.Mutable<Unit>(); + let elementCount = 0; + let isSorted = true; + let lastId = units.length > 0 ? units[0].id : 0; + for (let i = 0, _i = units.length; i < _i; i++) { + const u = units[i]; + map.set(u.id, u); + elementCount += u.elements.length; + if (u.id < lastId) isSorted = false; + lastId = u.id; + } + if (!isSorted) sort(units, 0, units.length, cmpUnits, arraySwap) + this.unitMap = map; + this.units = units as ReadonlyArray<Unit>; + this.elementCount = elementCount; + } } +function cmpUnits(units: ArrayLike<Unit>, i: number, j: number) { return units[i].id - units[j].id; } + namespace Structure { - 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 const Empty = new Structure([]); + + export function create(units: ReadonlyArray<Unit>): Structure { return new Structure(units); } export function ofData(format: Format) { const models = Model.create(format); @@ -31,81 +81,213 @@ namespace Structure { export function ofModel(model: Model): Structure { const chains = model.hierarchy.chainSegments; - const builder = Builder(); + const builder = new StructureBuilder(); for (let c = 0; c < chains.count; c++) { - const group = ElementGroup.createNew(OrderedSet.ofBounds(chains.segments[c], chains.segments[c + 1])); - const unit = Unit.create(Unit.Kind.Atomic, model, SymmetryOperator.Default, group); - builder.add(unit, unit.fullGroup); + const elements = SortedArray.ofBounds(chains.segments[c], chains.segments[c + 1]); + builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, elements); } const cs = model.coarseGrained; if (cs.isDefined) { if (cs.spheres.count > 0) { - const group = ElementGroup.createNew(OrderedSet.ofBounds(0, cs.spheres.count)); - const unit = Unit.create(Unit.Kind.Spheres, model, SymmetryOperator.Default, group); - builder.add(unit, unit.fullGroup); + const elements = SortedArray.ofBounds(0, cs.spheres.count); + builder.addUnit(Unit.Kind.Spheres, model, SymmetryOperator.Default, elements); } if (cs.gaussians.count > 0) { - const group = ElementGroup.createNew(OrderedSet.ofBounds(0, cs.gaussians.count)); - const unit = Unit.create(Unit.Kind.Gaussians, model, SymmetryOperator.Default, group); - builder.add(unit, unit.fullGroup); + const elements = SortedArray.ofBounds(0, cs.spheres.count); + builder.addUnit(Unit.Kind.Gaussians, model, SymmetryOperator.Default, elements); } } return builder.getStructure(); } - export interface Builder { - add(unit: Unit, elements: ElementGroup): void, - addUnit(unit: Unit): void, - setElements(unitId: number, elements: ElementGroup): void, - getStructure(): Structure, - readonly elementCount: number + export class StructureBuilder { + private units: Unit[] = []; + + addUnit(kind: Unit.Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit { + const unit = Unit.create(this.units.length, kind, model, operator, elements); + this.units.push(unit); + return unit; + } + + addWithOperator(unit: Unit, operator: SymmetryOperator): Unit { + const newUnit = unit.applyOperator(this.units.length, operator); + this.units.push(newUnit); + return newUnit; + } + + getStructure(): Structure { + return create(this.units); + } + + get isEmpty() { + return this.units.length === 0; + } } - class BuilderImpl implements Builder { - private _unitId = 0; - private units: Unit[] = []; - private elements = ElementSet.Generator(); + export function Builder() { return new StructureBuilder(); } + + export class SubsetBuilder { + private ids: number[] = []; + private unitMap = IntMap.Mutable<number[]>(); + private parentId = -1; + private currentUnit: number[] = []; elementCount = 0; - 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; } - 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); } - } + addToUnit(parentId: number, e: number) { + const unit = this.unitMap.get(parentId); + if (!!unit) { unit[unit.length] = e; } + else { + this.unitMap.set(parentId, [e]); + this.ids[this.ids.length] = parentId; + } + this.elementCount++; + } - export function Builder(): Builder { return new BuilderImpl(); } + beginUnit(parentId: number) { + this.parentId = parentId; + this.currentUnit = this.currentUnit.length > 0 ? [] : this.currentUnit; + } + + addElement(e: number) { + this.currentUnit[this.currentUnit.length] = e; + this.elementCount++; + } + + commitUnit() { + if (this.currentUnit.length === 0) return; + this.ids[this.ids.length] = this.parentId; + this.unitMap.set(this.parentId, this.currentUnit); + this.parentId = -1; + } + + setUnit(parentId: number, elements: ArrayLike<number>) { + this.ids[this.ids.length] = parentId; + this.unitMap.set(parentId, elements as number[]); + this.elementCount += elements.length; + } - /** Transient = location gets overwritten when move() is called. */ - 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)); + getStructure(): Structure { + if (this.isEmpty) return Structure.Empty; + + const newUnits: Unit[] = []; + sortArray(this.ids); + + for (let i = 0, _i = this.ids.length; i < _i; i++) { + const id = this.ids[i]; + const parent = this.parent.unitMap.get(id); + + const unit = this.unitMap.get(id); + const l = unit.length; + + // if the length is the same, just copy the old unit. + if (unit.length === parent.elements.length) { + newUnits[newUnits.length] = parent; + continue; + } + + if (!this.isSorted && l > 1) sortArray(unit); + + // TODO: checking if two units are equal in the same symmetry group to reuse computed properties. + newUnits[newUnits.length] = parent.getChild(SortedArray.ofSortedArray(unit)); + } + + return create(newUnits); + } + + singleton(): Element { + return Element.create(this.ids[0], this.unitMap.get(this.ids[0])[0]); + } + + get isEmpty() { + return this.elementCount === 0; + } + + constructor(private parent: Structure, private isSorted: boolean) { + + } } export function getModels(s: Structure) { - const { units, elements } = s; + const { units } = s; const arr = UniqueArray.create<Model['id'], Model>(); - const ids = ElementSet.unitIndices(elements); - for (let i = 0; i < ids.length; i++) { - const u = units[ids[i]]; + for (const u of units) { UniqueArray.add(arr, u.model.id, u.model); } return arr.array; } - export function getLookup3d(s: Structure) { - return ElementSet.getLookup3d(s); + export function getLookup3d(s: Structure): StructureLookup3D { + return 0 as any; } export function getBoundary(s: Structure) { return getLookup3d(s).boundary; } - // TODO: "lift" atom set operators? - // TODO: "diff" + export function hashCode(s: Structure) { + return s.hashCode; + } + + export function areEqual(a: Structure, b: Structure) { + if (a.elementCount !== b.elementCount) return false; + const len = a.units.length; + if (len !== b.units.length) return false; + + for (let i = 0; i < len; i++) { + if (a.units[i].id !== b.units[i].id) return false; + } + + for (let i = 0; i < len; i++) { + if (!SortedArray.areEqual(a.units[i].elements, b.units[i].elements)) return false; + } + + return true; + } + + export class ElementLocationIterator implements Iterator<Element.Location> { + private current = Element.Location(); + private unitIndex = 0; + private elements: SortedArray; + private len = 0; + private idx = 0; + + hasNext: boolean; + move(): Element.Location { + this.current.element = this.elements[this.idx]; + this.next(); + return this.current; + } + + private next() { + if (this.idx < this.len - 1) { + this.idx++; + return; + } + + this.idx = 0; + this.unitIndex++; + if (this.unitIndex >= this.structure.units.length) { + this.hasNext = false; + return; + } + + this.current.unit = this.structure.units[this.unitIndex]; + this.elements = this.current.unit.elements; + this.len = this.elements.length; + } + + constructor(private structure: Structure) { + this.hasNext = structure.elementCount > 0; + if (this.hasNext) { + this.elements = structure.units[0].elements; + this.len = this.elements.length; + this.current.unit = structure.units[0]; + } + } + } } export default Structure \ No newline at end of file diff --git a/src/mol-model/structure/structure/symmetry.ts b/src/mol-model/structure/structure/symmetry.ts index 7fe2fb2bb874e1402537df5ec312c3df5677e5ed..35f92e9d687e733aa2750e2de9e0e93d1cd79fd9 100644 --- a/src/mol-model/structure/structure/symmetry.ts +++ b/src/mol-model/structure/structure/symmetry.ts @@ -5,8 +5,6 @@ */ import Structure from './structure' -import ElementSet from './element/set' -import Unit from './unit' import { Selection } from '../query' import { ModelSymmetry } from '../model' import { Task } from 'mol-task'; @@ -29,15 +27,14 @@ function buildAssemblyImpl(structure: Structure, name: string) { for (const g of assembly.operatorGroups) { const selection = await ctx.runChild(g.selector(structure)); - if (Selection.structureCount(selection) === 0) continue; - const { units, elements } = Selection.unionStructure(selection); - - const unitIds = ElementSet.unitIndices(elements); + if (Selection.structureCount(selection) === 0) { + continue; + } + const { units } = Selection.unionStructure(selection); for (const oper of g.operators) { - for (let uI = 0, _uI = unitIds.length; uI < _uI; uI++) { - const unit = units[unitIds[uI]]; - assembler.add(Unit.withOperator(unit, oper), ElementSet.groupAt(elements, uI)); + for (const unit of units) { + assembler.addWithOperator(unit, oper); } } } diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index 3c82688a421d1aa5570778b92d753ace961d3b8c..3783235b27db700584f03ca632b698b2f528514c 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/src/mol-model/structure/structure/unit.ts @@ -10,6 +10,8 @@ import { Model } from '../model' import { GridLookup3D } from 'mol-math/geometry' import { computeUnitBonds } from './element/properties/bonds/group-compute'; import CoarseGrained from '../model/properties/coarse-grained'; +import { SortedArray } from 'mol-data/int'; +import { idFactory } from 'mol-util/id-factory'; // A building block of a structure that corresponds to an atomic or a coarse grained representation // 'conveniently grouped together'. @@ -23,18 +25,32 @@ namespace Unit { export function isSpheres(u: Unit): u is Spheres { return u.kind === Kind.Spheres; } export function isGaussians(u: Unit): u is Gaussians { return u.kind === Kind.Gaussians; } - export interface Base extends SymmetryOperator.ArrayMapping { - // Provides access to the underlying data. + export function create(id: number, kind: Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit { + switch (kind) { + case Kind.Atomic: return new Atomic(id, unitIdFactory(), model, elements, SymmetryOperator.createMapping(operator, model.atomSiteConformation)); + case Kind.Spheres: return createCoarse(id, unitIdFactory(), model, Kind.Spheres, model.coarseGrained.spheres, elements, SymmetryOperator.createMapping(operator, model.atomSiteConformation)); + case Kind.Gaussians: return createCoarse(id, unitIdFactory(), model, Kind.Gaussians, model.coarseGrained.gaussians, elements, SymmetryOperator.createMapping(operator, model.atomSiteConformation)); + } + } + + export function applyOperator(id: number, unit: Unit, operator: SymmetryOperator): Unit { + return create(id, unit.kind, unit.model, SymmetryOperator.compose(unit.conformation.operator, operator), unit.elements); + } + + export interface Base { + readonly id: number, + // invariant ID stays the same even if the Operator/conformation changes. + readonly invariantId: number, + readonly elements: SortedArray, readonly model: Model, + readonly conformation: SymmetryOperator.ArrayMapping, - // 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 + getChild(elements: SortedArray): Unit, + applyOperator(id: number, operator: SymmetryOperator): Unit } + const unitIdFactory = idFactory(); + // 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) @@ -42,85 +58,81 @@ namespace Unit { // // 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: Kind.Atomic, + export class Atomic implements Base { + readonly kind = Kind.Atomic; + + readonly id: number; + readonly invariantId: number; + readonly elements: SortedArray; + readonly model: Model; + readonly conformation: SymmetryOperator.ArrayMapping; // Reference some commonly accessed things for faster access. - readonly residueIndex: ArrayLike<number>, - readonly chainIndex: ArrayLike<number>, - readonly conformation: Model['atomSiteConformation'], - readonly hierarchy: Model['hierarchy'] + readonly residueIndex: ArrayLike<number>; + readonly chainIndex: ArrayLike<number>; + + getChild(elements: SortedArray): Unit { + return new Atomic(this.id, this.invariantId, this.model, elements, this.conformation); + } + + applyOperator(id: number, operator: SymmetryOperator): Unit { + const op = SymmetryOperator.compose(this.conformation.operator, operator); + return new Atomic(id, this.invariantId, this.model, this.elements, SymmetryOperator.createMapping(op, this.model.atomSiteConformation)); + } + + constructor(id: number, invariantId: number, model: Model, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping) { + this.id = id; + this.invariantId = invariantId; + this.model = model; + this.elements = elements; + this.conformation = conformation; + + this.residueIndex = model.hierarchy.residueSegments.segmentMap; + this.chainIndex = model.hierarchy.chainSegments.segmentMap; + } } // Coarse grained representations. - export interface CoarseBase<K extends Kind, S extends CoarseGrained.SitesBase> extends Base { - readonly kind: K, + export interface CoarseBase<S extends CoarseGrained.SitesBase> extends Base { readonly sites: S } - export interface Spheres extends CoarseBase<Kind.Spheres, CoarseGrained.Spheres> { } - export interface Gaussians extends CoarseBase<Kind.Gaussians, CoarseGrained.Gaussians> { } + class Coarse<S extends CoarseGrained.SitesBase> implements CoarseBase<S> { + readonly kind: Kind; - export function create(kind: Kind, model: Model, operator: SymmetryOperator, fullGroup: ElementGroup): Unit { - switch (kind) { - case Kind.Atomic: return createAtomic(model, operator, fullGroup); - case Kind.Spheres: return createSpheres(model, operator, fullGroup); - case Kind.Gaussians: return createGaussians(model, operator, fullGroup); + readonly id: number; + readonly invariantId: number; + readonly elements: SortedArray; + readonly model: Model; + readonly conformation: SymmetryOperator.ArrayMapping; + readonly sites: S; + + getChild(elements: SortedArray): Unit { + return createCoarse(this.id, this.invariantId, this.model, this.kind, this.sites, elements, this.conformation); } - } - function createAtomic(model: Model, operator: SymmetryOperator, fullGroup: ElementGroup): Unit.Atomic { - const h = model.hierarchy; - const { invariantPosition, position, x, y, z } = SymmetryOperator.createMapping(operator, model.atomSiteConformation); - - return { - model, - kind: Kind.Atomic, - operator, - fullGroup, - residueIndex: h.residueSegments.segmentMap, - chainIndex: h.chainSegments.segmentMap, - hierarchy: model.hierarchy, - conformation: model.atomSiteConformation, - invariantPosition, - position, - x, y, z - }; - } + applyOperator(id: number, operator: SymmetryOperator): Unit { + const op = SymmetryOperator.compose(this.conformation.operator, operator); + return createCoarse(id, this.invariantId, this.model, this.kind, this.sites, this.elements, SymmetryOperator.createMapping(op, this.sites)); + } - function createSpheres(model: Model, operator: SymmetryOperator, fullGroup: ElementGroup): Unit.Spheres { - const { invariantPosition, position, x, y, z } = SymmetryOperator.createMapping(operator, model.coarseGrained.spheres); - - return { - model, - kind: Kind.Spheres, - sites: model.coarseGrained.spheres, - operator, - fullGroup, - invariantPosition, - position, - x, y, z - }; + constructor(id: number, invariantId: number, model: Model, kind: Kind, sites: S, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping) { + this.kind = kind; + this.id = id; + this.invariantId = invariantId; + this.model = model; + this.elements = elements; + this.conformation = conformation; + this.sites = sites; + } } - function createGaussians(model: Model, operator: SymmetryOperator, fullGroup: ElementGroup): Unit.Gaussians { - const { invariantPosition, position, x, y, z } = SymmetryOperator.createMapping(operator, model.coarseGrained.gaussians); - - return { - model, - kind: Kind.Gaussians, - sites: model.coarseGrained.gaussians, - operator, - fullGroup, - invariantPosition, - position, - x, y, z - }; + function createCoarse<S extends CoarseGrained.SitesBase>(id: number, invariantId: number, model: Model, kind: Kind, sites: S, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping): Unit { + return new Coarse(id, invariantId, model, kind, sites, elements, conformation) as any as Unit /** lets call this an ugly temporary hack */; } - export function withOperator(unit: Unit, operator: SymmetryOperator): Unit { - return create(unit.kind, unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup); - } + export interface Spheres extends CoarseBase<CoarseGrained.Spheres> { kind: Kind.Spheres } + export interface Gaussians extends CoarseBase<CoarseGrained.Gaussians> { kind: Kind.Gaussians } export function getLookup3d(unit: Unit, group: ElementGroup) { if (group.__lookup3d__) return group.__lookup3d__; diff --git a/src/mol-model/structure/structure/unit/bonds/compute.ts b/src/mol-model/structure/structure/unit/bonds/compute.ts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/mol-model/structure/structure/unit/bonds/data.ts b/src/mol-model/structure/structure/unit/bonds/data.ts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/mol-model/structure/structure/util/boundary.ts b/src/mol-model/structure/structure/util/boundary.ts index 547d3828eb2f892bcdb9b8b620cebe36fc0a0610..2a595f8cd7551a060e19d12388e7ad222f55dfd7 100644 --- a/src/mol-model/structure/structure/util/boundary.ts +++ b/src/mol-model/structure/structure/util/boundary.ts @@ -5,8 +5,6 @@ */ import Structure from '../structure' -import ElementSet from '../element/set' -import { ElementGroup } from '../../structure' import { Box3D, Sphere3D } from 'mol-math/geometry'; import { Vec3 } from 'mol-math/linear-algebra'; @@ -14,19 +12,19 @@ function computeStructureBoundary(s: Structure): { box: Box3D, sphere: Sphere3D const min = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE]; const max = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE]; - const { units, elements } = s; + const { units } = s; let cx = 0, cy = 0, cz = 0; let radiusSq = 0; let size = 0; - for (let i = 0, _i = ElementSet.groupCount(elements); i < _i; i++) { - const group = ElementSet.groupAt(elements, i); - const { x, y, z } = units[ElementSet.groupUnitIndex(elements, i)]; + for (let i = 0, _i = units.length; i < _i; i++) { + const { x, y, z } = units[i].conformation; - size += ElementGroup.size(group); - for (let j = 0, _j = ElementGroup.size(group); j < _j; j++) { - const e = ElementGroup.getAt(group, j); + const elements = units[i].elements; + size += elements.length; + for (let j = 0, _j = elements.length; j < _j; j++) { + const e = elements[j]; const xx = x(e), yy = y(e), zz = z(e); min[0] = Math.min(xx, min[0]); @@ -48,13 +46,12 @@ function computeStructureBoundary(s: Structure): { box: Box3D, sphere: Sphere3D cz /= size; } - for (let i = 0, _i = ElementSet.groupCount(elements); i < _i; i++) { - const group = ElementSet.groupAt(elements, i); - const { x, y, z } = units[ElementSet.groupUnitIndex(elements, i)]; + for (let i = 0, _i = units.length; i < _i; i++) { + const { x, y, z } = units[i].conformation; - size += ElementGroup.size(group); - for (let j = 0, _j = ElementGroup.size(group); j < _j; j++) { - const e = ElementGroup.getAt(group, j); + const elements = units[i].elements; + for (let j = 0, _j = elements.length; j < _j; j++) { + const e = elements[j]; const dx = x(e) - cx, dy = y(e) - cy, dz = z(e) - cz; const d = dx * dx + dy * dy + dz * dz; if (d > radiusSq) radiusSq = d; diff --git a/src/mol-model/structure/structure/util/lookup3d.ts b/src/mol-model/structure/structure/util/lookup3d.ts index bb7230600205a39c78beeff7ac044b2d99a95d8d..8c8fc57e39404b9bddbbae63702aa06cc6f31e36 100644 --- a/src/mol-model/structure/structure/util/lookup3d.ts +++ b/src/mol-model/structure/structure/util/lookup3d.ts @@ -6,99 +6,99 @@ import Structure from '../structure' import Element from '../element' -import { Lookup3D, GridLookup3D, Result, Box3D, Sphere3D } from 'mol-math/geometry'; -import { ElementSet, Unit } from '../../structure'; -import { Vec3 } from 'mol-math/linear-algebra'; -import { OrderedSet } from 'mol-data/int'; -import { computeStructureBoundary } from './boundary'; +import { Lookup3D, /*GridLookup3D,*/ Result, Box3D, Sphere3D } from 'mol-math/geometry'; +//import { ElementSet, Unit } from '../../structure'; +//import { Vec3 } from 'mol-math/linear-algebra'; +//import { OrderedSet } from 'mol-data/int'; +//import { computeStructureBoundary } from './boundary'; -interface ElementSetLookup3D extends Lookup3D<Element> {} +interface StructureLookup3D extends Lookup3D<Element> {} -namespace ElementSetLookup3D { - class Impl implements ElementSetLookup3D { - private unitLookup: Lookup3D; +namespace StructureLookup3D { + class Impl implements StructureLookup3D { + //private unitLookup: Lookup3D; private result = Result.create<Element>(); - private pivot = Vec3.zero(); + //private pivot = Vec3.zero(); find(x: number, y: number, z: number, radius: number): Result<Element> { Result.reset(this.result); - const { units, elements } = this.structure; - const closeUnits = this.unitLookup.find(x, y, z, radius); - if (closeUnits.count === 0) return this.result; - - for (let t = 0, _t = closeUnits.count; t < _t; t++) { - const i = closeUnits.indices[t]; - const unitId = ElementSet.groupUnitIndex(elements, i); - const group = ElementSet.groupAt(elements, i); - const unit = units[unitId]; - Vec3.set(this.pivot, x, y, z); - if (!unit.operator.isIdentity) { - Vec3.transformMat4(this.pivot, this.pivot, unit.operator.inverse); - } - const groupLookup = Unit.getLookup3d(unit, group); - const groupResult = groupLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], radius); - for (let j = 0, _j = groupResult.count; j < _j; j++) { - Result.add(this.result, Element.create(unitId, groupResult.indices[j]), groupResult.squaredDistances[j]); - } - } + // const { units, elements } = this.structure; + // const closeUnits = this.unitLookup.find(x, y, z, radius); + // if (closeUnits.count === 0) return this.result; + + // for (let t = 0, _t = closeUnits.count; t < _t; t++) { + // const i = closeUnits.indices[t]; + // const unitId = ElementSet.groupUnitIndex(elements, i); + // const group = ElementSet.groupAt(elements, i); + // const unit = units[unitId]; + // Vec3.set(this.pivot, x, y, z); + // if (!unit.operator.isIdentity) { + // Vec3.transformMat4(this.pivot, this.pivot, unit.operator.inverse); + // } + // const groupLookup = Unit.getLookup3d(unit, group); + // const groupResult = groupLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], radius); + // for (let j = 0, _j = groupResult.count; j < _j; j++) { + // Result.add(this.result, Element.create(unitId, groupResult.indices[j]), groupResult.squaredDistances[j]); + // } + // } return this.result; } check(x: number, y: number, z: number, radius: number): boolean { - const { units, elements } = this.structure; - const closeUnits = this.unitLookup.find(x, y, z, radius); - if (closeUnits.count === 0) return false; - - for (let t = 0, _t = closeUnits.count; t < _t; t++) { - const i = closeUnits.indices[t]; - const unitId = ElementSet.groupUnitIndex(elements, i); - const group = ElementSet.groupAt(elements, i); - const unit = units[unitId]; - Vec3.set(this.pivot, x, y, z); - if (!unit.operator.isIdentity) { - Vec3.transformMat4(this.pivot, this.pivot, unit.operator.inverse); - } - const groupLookup = Unit.getLookup3d(unit, group); - if (groupLookup.check(this.pivot[0], this.pivot[1], this.pivot[2], radius)) return true; - } + // const { units, elements } = this.structure; + // const closeUnits = this.unitLookup.find(x, y, z, radius); + // if (closeUnits.count === 0) return false; + + // for (let t = 0, _t = closeUnits.count; t < _t; t++) { + // const i = closeUnits.indices[t]; + // const unitId = ElementSet.groupUnitIndex(elements, i); + // const group = ElementSet.groupAt(elements, i); + // const unit = units[unitId]; + // Vec3.set(this.pivot, x, y, z); + // if (!unit.operator.isIdentity) { + // Vec3.transformMat4(this.pivot, this.pivot, unit.operator.inverse); + // } + // const groupLookup = Unit.getLookup3d(unit, group); + // if (groupLookup.check(this.pivot[0], this.pivot[1], this.pivot[2], radius)) return true; + // } return false; } boundary: { box: Box3D; sphere: Sphere3D; }; - constructor(private structure: Structure) { - const { units, elements } = structure; - const unitCount = ElementSet.groupCount(elements); - const xs = new Float32Array(unitCount); - const ys = new Float32Array(unitCount); - const zs = new Float32Array(unitCount); - const radius = new Float32Array(unitCount); - - const center = Vec3.zero(); - for (let i = 0; i < unitCount; i++) { - const group = ElementSet.groupAt(elements, i); - const unit = units[ElementSet.groupUnitIndex(elements, i)]; - const lookup = Unit.getLookup3d(unit, group); - const s = lookup.boundary.sphere; - - Vec3.transformMat4(center, s.center, unit.operator.matrix); - - xs[i] = center[0]; - ys[i] = center[1]; - zs[i] = center[2]; - radius[i] = s.radius; - } - - this.unitLookup = GridLookup3D({ x: xs, y: ys, z: zs, radius, indices: OrderedSet.ofBounds(0, unitCount) }); - this.boundary = computeStructureBoundary(structure); + constructor(structure: Structure) { + // const { units, elements } = structure; + // const unitCount = ElementSet.groupCount(elements); + // const xs = new Float32Array(unitCount); + // const ys = new Float32Array(unitCount); + // const zs = new Float32Array(unitCount); + // const radius = new Float32Array(unitCount); + + // const center = Vec3.zero(); + // for (let i = 0; i < unitCount; i++) { + // const group = ElementSet.groupAt(elements, i); + // const unit = units[ElementSet.groupUnitIndex(elements, i)]; + // const lookup = Unit.getLookup3d(unit, group); + // const s = lookup.boundary.sphere; + + // Vec3.transformMat4(center, s.center, unit.operator.matrix); + + // xs[i] = center[0]; + // ys[i] = center[1]; + // zs[i] = center[2]; + // radius[i] = s.radius; + // } + + // this.unitLookup = GridLookup3D({ x: xs, y: ys, z: zs, radius, indices: OrderedSet.ofBounds(0, unitCount) }); + // this.boundary = computeStructureBoundary(structure); } } - export function create(s: Structure): ElementSetLookup3D { + export function create(s: Structure): StructureLookup3D { return new Impl(s); } } -export { ElementSetLookup3D } \ No newline at end of file +export { StructureLookup3D } \ No newline at end of file diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts index 03f04a2333d8fcfcc8af2b31f9b2b7cc02036255..65608d08b1f7812b80e3387900899d95650192c9 100644 --- a/src/perf-tests/structure.ts +++ b/src/perf-tests/structure.ts @@ -11,12 +11,12 @@ import * as fs from 'fs' import fetch from 'node-fetch' import CIF from 'mol-io/reader/cif' -import { Structure, Model, Queries as Q, Element, ElementGroup, ElementSet, Selection, Symmetry, Unit, Query } from 'mol-model/structure' -import { Segmentation, OrderedSet } from 'mol-data/int' +import { Structure, Model, Queries as Q, Element, Selection, Symmetry, Query } from 'mol-model/structure' +//import { Segmentation, OrderedSet } from 'mol-data/int' import to_mmCIF from 'mol-model/structure/export/mmcif' import { Run } from 'mol-task'; -import { EquivalenceClasses } from 'mol-data/util'; +//import { EquivalenceClasses } from 'mol-data/util'; require('util.promisify').shim(); const readFileAsync = util.promisify(fs.readFile); @@ -119,19 +119,14 @@ export namespace PropertyAccess { } function sumProperty(structure: Structure, p: Element.Property<number>) { - const { elements, units } = structure; - const unitIds = ElementSet.unitIndices(elements); const l = Element.Location(); - let s = 0; - for (let i = 0, _i = unitIds.length; i < _i; i++) { - l.unit = units[unitIds[i]]; - const set = ElementSet.groupAt(elements, i); - - - for (let j = 0, _j = ElementGroup.size(set); j < _j; j++) { - l.element= ElementGroup.getAt(set, j); + for (const unit of structure.units) { + l.unit = unit; + const elements = unit.elements; + for (let j = 0, _j = elements.length; j < _j; j++) { + l.element = elements[j]; s += p(l); } } @@ -139,44 +134,44 @@ export namespace PropertyAccess { return s; } - function sumPropertySegmented(structure: Structure, p: Element.Property<number>) { - const { elements, units } = structure; - const unitIds = ElementSet.unitIndices(elements); - const l = Element.Location(); + // function sumPropertySegmented(structure: Structure, p: Element.Property<number>) { + // const { elements, units } = structure; + // const unitIds = ElementSet.unitIndices(elements); + // const l = Element.Location(); - let s = 0; + // let s = 0; - let vA = 0, cC = 0, rC = 0; - for (let i = 0, _i = unitIds.length; i < _i; i++) { - const unit = units[unitIds[i]] as Unit.Atomic; - l.unit = unit; - const set = ElementSet.groupAt(elements, i); - - const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set.elements); - const residues = unit.hierarchy.residueSegments; - while (chainsIt.hasNext) { - cC++; - - const chainSegment = chainsIt.move(); - const residuesIt = Segmentation.transientSegments(residues, set.elements, chainSegment); - while (residuesIt.hasNext) { - rC++; - const residueSegment = residuesIt.move(); - // 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)) - for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { - l.element= ElementGroup.getAt(set, j); - vA++; - s += p(l); - } - } - } - } + // let vA = 0, cC = 0, rC = 0; + // for (let i = 0, _i = unitIds.length; i < _i; i++) { + // const unit = units[unitIds[i]] as Unit.Atomic; + // l.unit = unit; + // const set = ElementSet.groupAt(elements, i); - console.log('seg atom count', vA, cC, rC); + // const chainsIt = Segmentation.transientSegments(unit.hierarchy.chainSegments, set.elements); + // const residues = unit.hierarchy.residueSegments; + // while (chainsIt.hasNext) { + // cC++; - return s; - } + // const chainSegment = chainsIt.move(); + // const residuesIt = Segmentation.transientSegments(residues, set.elements, chainSegment); + // while (residuesIt.hasNext) { + // rC++; + // const residueSegment = residuesIt.move(); + // // 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)) + // for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { + // l.element= ElementGroup.getAt(set, j); + // vA++; + // s += p(l); + // } + // } + // } + // } + + // console.log('seg atom count', vA, cC, rC); + + // return s; + // } // function sumPropertyResidue(structure: Structure, p: Element.Property<number>) { // const { atoms, units } = structure; @@ -199,20 +194,20 @@ export namespace PropertyAccess { // return s; // } - function sumPropertyAtomSetIt(structure: Structure, p: Element.Property<number>) { - const { elements, units } = structure; + // function sumPropertyAtomSetIt(structure: Structure, p: Element.Property<number>) { + // const { elements, units } = structure; - let s = 0; - const atomsIt = ElementSet.elements(elements); - const l = Element.Location(); - while (atomsIt.hasNext) { - const a = atomsIt.move(); - l.unit = units[Element.unit(a)]; - l.element= Element.index(a); - s += p(l); - } - return s; - } + // let s = 0; + // const atomsIt = ElementSet.elements(elements); + // const l = Element.Location(); + // while (atomsIt.hasNext) { + // const a = atomsIt.move(); + // l.unit = units[Element.unit(a)]; + // l.element= Element.index(a); + // s += p(l); + // } + // return s; + // } // function sumPropertySegmentedMutable(structure: Structure, p: Property<number>) { // const { atoms, units } = structure; @@ -302,24 +297,24 @@ export namespace PropertyAccess { console.log('exported'); } - export async function testGrouping(structure: Structure) { - const { elements, units } = await Run(Symmetry.buildAssembly(structure, '1')); - console.log('grouping', units.length); - console.log('built asm'); + // export async function testGrouping(structure: Structure) { + // const { elements, units } = await Run(Symmetry.buildAssembly(structure, '1')); + // console.log('grouping', units.length); + // console.log('built asm'); - const uniqueGroups = EquivalenceClasses<number, { unit: Unit, group: ElementGroup }>( - ({ unit, group }) => ElementGroup.hashCode(group), - (a, b) => a.unit.model.id === b.unit.model.id && (a.group.key === b.group.key && OrderedSet.areEqual(a.group.elements, b.group.elements)) - ); + // const uniqueGroups = EquivalenceClasses<number, { unit: Unit, group: ElementGroup }>( + // ({ unit, group }) => ElementGroup.hashCode(group), + // (a, b) => a.unit.model.id === b.unit.model.id && (a.group.key === b.group.key && OrderedSet.areEqual(a.group.elements, b.group.elements)) + // ); - for (let i = 0, _i = ElementSet.groupCount(elements); i < _i; i++) { - const group = ElementSet.groupAt(elements, i); - const unitId = ElementSet.groupUnitIndex(elements, i); - uniqueGroups.add(unitId, { unit: units[unitId], group }); - } + // for (let i = 0, _i = ElementSet.groupCount(elements); i < _i; i++) { + // const group = ElementSet.groupAt(elements, i); + // const unitId = ElementSet.groupUnitIndex(elements, i); + // uniqueGroups.add(unitId, { unit: units[unitId], group }); + // } - console.log('group count', uniqueGroups.groups.length); - } + // console.log('group count', uniqueGroups.groups.length); + // } function query(q: Query, s: Structure) { return Run((q(s))); @@ -330,17 +325,17 @@ export namespace PropertyAccess { // const { structures, models } = await getBcif('3j3q'); const { structures, models /*, mmcif*/ } = await readCIF('e:/test/quick/1hrv_updated.cif'); - const { structures: s1, /*, mmcif*/ } = await readCIF('e:/test/quick/1tqn_updated.cif'); + //const { structures: s1, /*, mmcif*/ } = await readCIF('e:/test/quick/1tqn_updated.cif'); - testGrouping(structures[0]); - console.log('------'); - testGrouping(s1[0]); + // testGrouping(structures[0]); + // console.log('------'); + // testGrouping(s1[0]); //const { structures, models/*, mmcif*/ } = await readCIF('e:/test/quick/5j7v_updated.cif'); //console.log(mmcif.pdbx_struct_oper_list.matrix.toArray()); // console.log(mmcif.pdbx_struct_oper_list.vector.toArray()); - // testAssembly('5j7v', structures[0]); + await testAssembly('1hrv', structures[0]); // throw ''; // console.log(models[0].symmetry.assemblies); @@ -357,10 +352,10 @@ export namespace PropertyAccess { console.log('bs', baseline(models[0])); console.log('sp', sumProperty(structures[0], l => l.unit.model.atomSiteConformation.atomId.value(l.element))); - console.log(sumPropertySegmented(structures[0], l => l.unit.model.atomSiteConformation.atomId.value(l.element))); + //console.log(sumPropertySegmented(structures[0], l => l.unit.model.atomSiteConformation.atomId.value(l.element))); //console.log(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.element)); - console.log(sumPropertyAtomSetIt(structures[0], l => l.unit.model.atomSiteConformation.atomId.value(l.element))); + //console.log(sumPropertyAtomSetIt(structures[0], l => l.unit.model.atomSiteConformation.atomId.value(l.element))); //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]))); @@ -403,14 +398,14 @@ export namespace PropertyAccess { console.log(Selection.structureCount(q2r)); //console.log(q1(structures[0])); - //const col = models[0].conformation.atomId.value; + const col = models[0].atomSiteConformation.atomId.value; const suite = new B.Suite(); suite //.add('test q', () => q1(structures[0])) //.add('test q', () => q(structures[0])) + .add('test int', () => sumProperty(structures[0], l => col(l.element))) .add('test q1', async () => await q1(structures[0])) .add('test q3', async () => await q3(structures[0])) - //.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('baseline', () => baseline(models[0]))