123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- /**
- * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
- import { StructureQuery } from '../query'
- import { StructureSelection } from '../selection'
- import { Unit, StructureProperties as P } from '../../structure'
- import { Segmentation, SortedArray } from 'mol-data/int'
- import { LinearGroupingBuilder } from '../utils/builders';
- import { QueryPredicate, QueryFn, QueryContextView } from '../context';
- import { UnitRing } from '../../structure/unit/rings';
- import Structure from '../../structure/structure';
- import { ElementIndex } from '../../model';
- import { UniqueArray } from 'mol-data/generic';
- import { structureSubtract } from '../utils/structure-set';
- export const none: StructureQuery = ctx => StructureSelection.Sequence(ctx.inputStructure, []);
- export const all: StructureQuery = ctx => StructureSelection.Singletons(ctx.inputStructure, ctx.inputStructure);
- export interface AtomsQueryParams {
- /** Query to be executed for each entity once */
- entityTest: QueryPredicate,
- /** Query to be executed for each chain once */
- chainTest: QueryPredicate,
- /** Query to be executed for each residue once */
- residueTest: QueryPredicate,
- /** Query to be executed for each atom */
- atomTest: QueryPredicate,
- groupBy: QueryFn
- }
- export function residues(params?: Partial<AtomsQueryParams>) { return atoms({ ...params, groupBy: ctx => P.residue.key(ctx.element) }); }
- export function chains(params?: Partial<AtomsQueryParams>) { return atoms({ ...params, groupBy: ctx => P.chain.key(ctx.element) }); }
- function _true(ctx: QueryContextView) { return true; }
- function _zero(ctx: QueryContextView) { return 0; }
- export function atoms(params?: Partial<AtomsQueryParams>): StructureQuery {
- if (!params || (!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy)) return all;
- if (!!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy) return atomGroupsLinear(params.atomTest);
- const normalized: AtomsQueryParams = {
- entityTest: params.entityTest || _true,
- chainTest: params.chainTest || _true,
- residueTest: params.residueTest || _true,
- atomTest: params.atomTest || _true,
- groupBy: params.groupBy || _zero,
- };
- if (!params.groupBy) return atomGroupsSegmented(normalized)
- return atomGroupsGrouped(normalized);
- }
- function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
- return ctx => {
- const { inputStructure } = ctx;
- const { units } = inputStructure;
- const l = ctx.pushCurrentElement();
- const builder = inputStructure.subsetBuilder(true);
- for (const unit of units) {
- l.unit = unit;
- const elements = unit.elements;
- builder.beginUnit(unit.id);
- for (let j = 0, _j = elements.length; j < _j; j++) {
- l.element = elements[j];
- if (atomTest(ctx)) builder.addElement(l.element);
- }
- builder.commitUnit();
- ctx.throwIfTimedOut();
- }
- ctx.popCurrentElement();
- return StructureSelection.Singletons(inputStructure, builder.getStructure());
- };
- }
- function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomsQueryParams): StructureQuery {
- return ctx => {
- const { inputStructure } = ctx;
- const { units } = inputStructure;
- const l = ctx.pushCurrentElement();
- const builder = inputStructure.subsetBuilder(true);
- for (const unit of units) {
- if (unit.kind !== Unit.Kind.Atomic) continue;
- l.unit = unit;
- const elements = unit.elements;
- builder.beginUnit(unit.id);
- const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, elements);
- const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, elements);
- while (chainsIt.hasNext) {
- const chainSegment = chainsIt.move();
- l.element = elements[chainSegment.start];
- // test entity and chain
- if (!entityTest(ctx) || !chainTest(ctx)) continue;
- residuesIt.setSegment(chainSegment);
- while (residuesIt.hasNext) {
- const residueSegment = residuesIt.move();
- l.element = elements[residueSegment.start];
- // test residue
- if (!residueTest(ctx)) continue;
- for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
- l.element = elements[j];
- if (atomTest(ctx)) {
- builder.addElement(l.element);
- }
- }
- }
- }
- builder.commitUnit();
- ctx.throwIfTimedOut();
- }
- ctx.popCurrentElement();
- return StructureSelection.Singletons(inputStructure, builder.getStructure());
- };
- }
- function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomsQueryParams): StructureQuery {
- return ctx => {
- const { inputStructure } = ctx;
- const { units } = inputStructure;
- const l = ctx.pushCurrentElement();
- const builder = new LinearGroupingBuilder(inputStructure);
- for (const unit of units) {
- if (unit.kind !== Unit.Kind.Atomic) continue;
- l.unit = unit;
- const elements = unit.elements;
- const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, elements);
- const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, elements);
- while (chainsIt.hasNext) {
- const chainSegment = chainsIt.move();
- l.element = elements[chainSegment.start];
- // test entity and chain
- if (!entityTest(ctx) || !chainTest(ctx)) continue;
- residuesIt.setSegment(chainSegment);
- while (residuesIt.hasNext) {
- const residueSegment = residuesIt.move();
- l.element = elements[residueSegment.start];
- // test residue
- if (!residueTest(ctx)) continue;
- for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
- l.element = elements[j];
- if (atomTest(ctx)) builder.add(groupBy(ctx), unit.id, l.element);
- }
- }
- }
- ctx.throwIfTimedOut();
- }
- ctx.popCurrentElement();
- return builder.getSelection();
- };
- }
- function getRingStructure(unit: Unit.Atomic, ring: UnitRing, inputStructure: Structure) {
- const elements = new Int32Array(ring.length) as any as ElementIndex[];
- for (let i = 0, _i = ring.length; i < _i; i++) elements[i] = unit.elements[ring[i]];
- return Structure.create([unit.getChild(SortedArray.ofSortedArray(elements))], inputStructure);
- }
- export function rings(fingerprints?: ArrayLike<UnitRing.Fingerprint>): StructureQuery {
- return ctx => {
- const { units } = ctx.inputStructure;
- let ret = StructureSelection.LinearBuilder(ctx.inputStructure);
- if (!fingerprints || fingerprints.length === 0) {
- for (const u of units) {
- if (!Unit.isAtomic(u)) continue;
- for (const r of u.rings.all) {
- ret.add(getRingStructure(u, r, ctx.inputStructure));
- }
- }
- } else {
- const uniqueFps = UniqueArray.create<UnitRing.Fingerprint, UnitRing.Fingerprint>();
- for (let i = 0; i < fingerprints.length; i++) UniqueArray.add(uniqueFps, fingerprints[i], fingerprints[i]);
- for (const u of units) {
- if (!Unit.isAtomic(u)) continue;
- const rings = u.rings;
- for (const fp of uniqueFps.array) {
- if (!rings.byFingerprint.has(fp)) continue;
- for (const r of rings.byFingerprint.get(fp)!) {
- ret.add(getRingStructure(u, rings.all[r], ctx.inputStructure));
- }
- }
- }
- }
- return ret.getSelection();
- }
- }
- export function querySelection(selection: StructureQuery, query: StructureQuery, inComplement: boolean = false): StructureQuery {
- return ctx => {
- const targetSel = selection(ctx);
- if (StructureSelection.structureCount(targetSel) === 0) return targetSel;
- const target = inComplement
- ? structureSubtract(ctx.inputStructure, StructureSelection.unionStructure(targetSel))
- : StructureSelection.unionStructure(targetSel);
- if (target.elementCount === 0) return StructureSelection.Empty(ctx.inputStructure);
- ctx.throwIfTimedOut();
- ctx.pushInputStructure(target);
- const result = query(ctx);
- ctx.popInputStructure();
- return StructureSelection.withInputStructure(result, ctx.inputStructure);
- }
- }
|