index-pair.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /**
  2. * Copyright (c) 2019-2023 Mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. * @author David Sehnal <david.sehnal@gmail.com>
  6. */
  7. import { CustomPropertyDescriptor } from '../../../../mol-model/custom-property';
  8. import { IntAdjacencyGraph } from '../../../../mol-math/graph';
  9. import { Column } from '../../../../mol-data/db';
  10. import { FormatPropertyProvider } from '../../common/property';
  11. import { BondType } from '../../../../mol-model/structure/model/types';
  12. import { ElementIndex } from '../../../../mol-model/structure';
  13. export type IndexPairsProps = {
  14. readonly key: ArrayLike<number>
  15. readonly operatorA: ArrayLike<number>
  16. readonly operatorB: ArrayLike<number>
  17. readonly order: ArrayLike<number>
  18. readonly distance: ArrayLike<number>
  19. readonly flag: ArrayLike<BondType.Flag>
  20. }
  21. export type IndexPairs = IntAdjacencyGraph<ElementIndex, IndexPairsProps>
  22. export type IndexPairBonds = { bonds: IndexPairs, maxDistance: number }
  23. function getGraph(indexA: ArrayLike<ElementIndex>, indexB: ArrayLike<ElementIndex>, props: Partial<IndexPairsProps>, count: number): IndexPairs {
  24. const builder = new IntAdjacencyGraph.EdgeBuilder(count, indexA, indexB);
  25. const key = new Int32Array(builder.slotCount);
  26. const operatorA = new Array(builder.slotCount);
  27. const operatorB = new Array(builder.slotCount);
  28. const order = new Int8Array(builder.slotCount);
  29. const distance = new Array(builder.slotCount);
  30. const flag = new Array(builder.slotCount);
  31. for (let i = 0, _i = builder.edgeCount; i < _i; i++) {
  32. builder.addNextEdge();
  33. builder.assignProperty(key, props.key ? props.key[i] : -1);
  34. builder.assignDirectedProperty(
  35. operatorA, props.operatorA ? props.operatorA[i] : -1,
  36. operatorB, props.operatorB ? props.operatorB[i] : -1
  37. );
  38. builder.assignProperty(order, props.order ? props.order[i] : 1);
  39. builder.assignProperty(distance, props.distance ? props.distance[i] : -1);
  40. builder.assignProperty(flag, props.flag ? props.flag[i] : BondType.Flag.Covalent);
  41. }
  42. return builder.createGraph({ key, operatorA, operatorB, order, distance, flag });
  43. }
  44. export namespace IndexPairBonds {
  45. export const Descriptor: CustomPropertyDescriptor = {
  46. name: 'index_pair_bonds',
  47. };
  48. export const Provider = FormatPropertyProvider.create<IndexPairBonds>(Descriptor, { asDynamic: true });
  49. export type Data = {
  50. pairs: {
  51. indexA: Column<number>,
  52. indexB: Column<number>,
  53. key?: Column<number>,
  54. /** Operator key for indexA. Used in bond computation. */
  55. operatorA?: Column<number>,
  56. /** Operator key for indexB. Used in bond computation. */
  57. operatorB?: Column<number>,
  58. order?: Column<number>,
  59. /**
  60. * Useful for bonds in periodic cells. That is, only bonds within the given
  61. * distance are added. This allows for bond between periodic image but
  62. * avoids unwanted bonds with wrong distances. If negative, test using the
  63. * `maxDistance` option from `Props`.
  64. */
  65. distance?: Column<number>,
  66. flag?: Column<BondType.Flag>,
  67. },
  68. count: number
  69. }
  70. export const DefaultProps = {
  71. /**
  72. * If negative, test using element-based threshold, otherwise distance in Angstrom.
  73. *
  74. * This option exists to handle bonds in periodic cells. For systems that are
  75. * made from beads (as opposed to atomic elements), set to a specific distance.
  76. *
  77. * Note that `Data` has a `distance` field which allows specifying a distance
  78. * for each bond individually which takes precedence over this option.
  79. */
  80. maxDistance: -1
  81. };
  82. export type Props = typeof DefaultProps
  83. export function fromData(data: Data, props: Partial<Props> = {}): IndexPairBonds {
  84. const p = { ...DefaultProps, ...props };
  85. const { pairs, count } = data;
  86. const indexA = pairs.indexA.toArray() as ArrayLike<ElementIndex>;
  87. const indexB = pairs.indexB.toArray() as ArrayLike<ElementIndex>;
  88. const key = pairs.key && pairs.key.toArray();
  89. const operatorA = pairs.operatorA && pairs.operatorA.toArray();
  90. const operatorB = pairs.operatorB && pairs.operatorB.toArray();
  91. const order = pairs.order && pairs.order.toArray();
  92. const distance = pairs.distance && pairs.distance.toArray();
  93. const flag = pairs.flag && pairs.flag.toArray();
  94. return {
  95. bonds: getGraph(indexA, indexB, { key, operatorA, operatorB, order, distance, flag }, count),
  96. maxDistance: p.maxDistance
  97. };
  98. }
  99. /** Like `getEdgeIndex` but taking `edgeProps.operatorA` and `edgeProps.operatorB` into account */
  100. export function getEdgeIndexForOperators(bonds: IndexPairs, i: ElementIndex, j: ElementIndex, opI: number, opJ: number): number {
  101. let a, b, opA, opB;
  102. if (i < j) {
  103. a = i; b = j;
  104. opA = opI; opB = opJ;
  105. } else {
  106. a = j; b = i;
  107. opA = opJ; opB = opI;
  108. }
  109. for (let t = bonds.offset[a], _t = bonds.offset[a + 1]; t < _t; t++) {
  110. if (bonds.b[t] === b && bonds.edgeProps.operatorA[t] === opA && bonds.edgeProps.operatorB[t] === opB) return t;
  111. }
  112. return -1;
  113. }
  114. }