indexed.ts 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { ResidueIndex, ChainIndex, ElementIndex } from '../../indexing';
  7. import { Unit, Structure, StructureElement } from '../../../structure';
  8. import { Segmentation } from 'mol-data/int';
  9. import { UUID } from 'mol-util';
  10. import { CifWriter } from 'mol-io/writer/cif';
  11. import { Model } from '../../model';
  12. export class IndexedCustomProperty<Idx extends IndexedCustomProperty.Index, T = any> {
  13. readonly id: UUID = UUID.create();
  14. readonly kind: Unit.Kind;
  15. has(idx: Idx): boolean { return this.map.has(idx); }
  16. get(idx: Idx) { return this.map.get(idx); }
  17. private getStructureElements(structure: Structure) {
  18. const models = structure.models;
  19. if (models.length !== 1) throw new Error(`Only works on structures with a single model.`);
  20. const seenIndices = new Set<Idx>();
  21. const unitGroups = structure.unitSymmetryGroups;
  22. const loci: StructureElement[] = [];
  23. const segments = this.segmentGetter(models[0])
  24. for (const unitGroup of unitGroups) {
  25. const unit = unitGroup.units[0];
  26. if (unit.kind !== this.kind) {
  27. continue;
  28. }
  29. const chains = Segmentation.transientSegments(segments, unit.elements);
  30. while (chains.hasNext) {
  31. const seg = chains.move();
  32. if (!this.has(seg.index) || seenIndices.has(seg.index)) continue;
  33. seenIndices.add(seg.index);
  34. loci[loci.length] = StructureElement.create(unit, unit.elements[seg.start]);
  35. }
  36. }
  37. loci.sort((x, y) => x.element - y.element);
  38. return loci;
  39. }
  40. getExportContext(structure: Structure): IndexedCustomProperty.ExportCtx<T> {
  41. const index = this.segmentGetter(structure.model).index;
  42. const elements = this.getStructureElements(structure);
  43. return { elements, property: i => this.get(index[elements[i].element])! };
  44. }
  45. constructor(private map: Map<Idx, T>, private segmentGetter: (model: Model) => Segmentation<ElementIndex, Idx>, kind: Unit.Kind) {
  46. this.kind = kind;
  47. }
  48. }
  49. export namespace IndexedCustomProperty {
  50. export type Index = ResidueIndex | ChainIndex
  51. export interface ExportCtx<T> {
  52. elements: StructureElement[],
  53. property(index: number): T
  54. }
  55. export function getCifDataSource<Idx extends Index, T>(structure: Structure, prop: IndexedCustomProperty<Idx, T> | undefined, cache: any): CifWriter.Category.Instance['source'][0] {
  56. if (!prop) return { rowCount: 0 };
  57. if (cache && cache[prop.id]) return cache[prop.id];
  58. const data = prop.getExportContext(structure);
  59. const ret = { data, rowCount: data.elements.length };
  60. if (cache) cache[prop.id] = ret;
  61. return ret;
  62. }
  63. export type Residue<T> = IndexedCustomProperty<ResidueIndex, T>
  64. const getResidueSegments = (model: Model) => model.atomicHierarchy.residueAtomSegments;
  65. export function fromResidueMap<T>(map: Map<ResidueIndex, T>, kind: Unit.Kind): Residue<T> {
  66. return new IndexedCustomProperty(map, getResidueSegments, kind);
  67. }
  68. export type Chain<T> = IndexedCustomProperty<ChainIndex, T>
  69. const getChainSegments = (model: Model) => model.atomicHierarchy.chainAtomSegments;
  70. export function fromChainMap<T>(map: Map<ChainIndex, T>, kind: Unit.Kind): Chain<T> {
  71. return new IndexedCustomProperty(map, getChainSegments, kind);
  72. }
  73. }