generators.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { StructureQuery } from './query'
  7. import { StructureSelection } from './selection'
  8. import { Unit, StructureProperties as P } from '../structure'
  9. import { Segmentation } from 'mol-data/int'
  10. import { LinearGroupingBuilder } from './utils/builders';
  11. import { QueryPredicate, QueryFn, QueryContextView } from './context';
  12. export const all: StructureQuery = async (ctx) => StructureSelection.Singletons(ctx.structure, ctx.structure);
  13. export interface AtomsQueryParams {
  14. entityTest: QueryPredicate,
  15. chainTest: QueryPredicate,
  16. residueTest: QueryPredicate,
  17. atomTest: QueryPredicate,
  18. groupBy: QueryFn
  19. }
  20. export function residues(params?: Partial<AtomsQueryParams>) { return atoms({ ...params, groupBy: ctx => P.residue.key(ctx.element) }); }
  21. export function chains(params?: Partial<AtomsQueryParams>) { return atoms({ ...params, groupBy: ctx => P.chain.key(ctx.element) }); }
  22. function _true(ctx: QueryContextView) { return true; }
  23. function _zero(ctx: QueryContextView) { return 0; }
  24. export function atoms(params?: Partial<AtomsQueryParams>): StructureQuery {
  25. if (!params || (!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy)) return all;
  26. if (!!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy) return atomGroupsLinear(params.atomTest);
  27. const normalized: AtomsQueryParams = {
  28. entityTest: params.entityTest || _true,
  29. chainTest: params.chainTest || _true,
  30. residueTest: params.residueTest || _true,
  31. atomTest: params.atomTest || _true,
  32. groupBy: params.groupBy || _zero,
  33. };
  34. if (!params.groupBy) return atomGroupsSegmented(normalized)
  35. return atomGroupsGrouped(normalized);
  36. }
  37. function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
  38. return async (ctx) => {
  39. const { structure } = ctx;
  40. const { units } = structure;
  41. const l = ctx.pushCurrentElement();
  42. const builder = structure.subsetBuilder(true);
  43. let progress = 0;
  44. for (const unit of units) {
  45. l.unit = unit;
  46. const elements = unit.elements;
  47. builder.beginUnit(unit.id);
  48. for (let j = 0, _j = elements.length; j < _j; j++) {
  49. l.element = elements[j];
  50. if (atomTest(ctx)) builder.addElement(l.element);
  51. }
  52. builder.commitUnit();
  53. progress++;
  54. if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
  55. }
  56. ctx.popCurrentElement();
  57. return StructureSelection.Singletons(structure, builder.getStructure());
  58. };
  59. }
  60. function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomsQueryParams): StructureQuery {
  61. return async (ctx) => {
  62. const { structure } = ctx;
  63. const { units } = structure;
  64. const l = ctx.pushCurrentElement();
  65. const builder = structure.subsetBuilder(true);
  66. let progress = 0;
  67. for (const unit of units) {
  68. if (unit.kind !== Unit.Kind.Atomic) continue;
  69. l.unit = unit;
  70. const elements = unit.elements;
  71. builder.beginUnit(unit.id);
  72. const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, elements);
  73. const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, elements);
  74. while (chainsIt.hasNext) {
  75. const chainSegment = chainsIt.move();
  76. l.element = elements[chainSegment.start];
  77. // test entity and chain
  78. if (!entityTest(ctx) || !chainTest(ctx)) continue;
  79. residuesIt.setSegment(chainSegment);
  80. while (residuesIt.hasNext) {
  81. const residueSegment = residuesIt.move();
  82. l.element = elements[residueSegment.start];
  83. // test residue
  84. if (!residueTest(ctx)) continue;
  85. for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
  86. l.element = elements[j];
  87. if (atomTest(ctx)) {
  88. builder.addElement(l.element);
  89. }
  90. }
  91. }
  92. }
  93. builder.commitUnit();
  94. progress++;
  95. if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
  96. }
  97. ctx.popCurrentElement();
  98. return StructureSelection.Singletons(structure, builder.getStructure());
  99. };
  100. }
  101. function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomsQueryParams): StructureQuery {
  102. return async (ctx) => {
  103. const { structure } = ctx;
  104. const { units } = structure;
  105. const l = ctx.pushCurrentElement();
  106. const builder = new LinearGroupingBuilder(structure);
  107. let progress = 0;
  108. for (const unit of units) {
  109. if (unit.kind !== Unit.Kind.Atomic) continue;
  110. l.unit = unit;
  111. const elements = unit.elements;
  112. const chainsIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, elements);
  113. const residuesIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, elements);
  114. while (chainsIt.hasNext) {
  115. const chainSegment = chainsIt.move();
  116. l.element = elements[chainSegment.start];
  117. // test entity and chain
  118. if (!entityTest(ctx) || !chainTest(ctx)) continue;
  119. residuesIt.setSegment(chainSegment);
  120. while (residuesIt.hasNext) {
  121. const residueSegment = residuesIt.move();
  122. l.element = elements[residueSegment.start];
  123. // test residue
  124. if (!residueTest(ctx)) continue;
  125. for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
  126. l.element = elements[j];
  127. if (atomTest(ctx)) builder.add(groupBy(ctx), unit.id, l.element);
  128. }
  129. }
  130. }
  131. progress++;
  132. if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
  133. }
  134. ctx.popCurrentElement();
  135. return builder.getSelection();
  136. };
  137. }