helix-orientation.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /**
  2. * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { ElementIndex } from '../../../mol-model/structure';
  7. import { Segmentation } from '../../../mol-data/int/segmentation';
  8. import { SortedRanges } from '../../../mol-data/int/sorted-ranges';
  9. import { OrderedSet } from '../../../mol-data/int';
  10. import { Model } from '../../../mol-model/structure/model';
  11. import { Vec3 } from '../../../mol-math/linear-algebra';
  12. export interface HelixOrientation {
  13. centers: ArrayLike<number>
  14. }
  15. /** Usees same definition as GROMACS' helixorient */
  16. export function calcHelixOrientation(model: Model): HelixOrientation {
  17. const { x, y, z } = model.atomicConformation;
  18. const { polymerType, traceElementIndex } = model.atomicHierarchy.derived.residue;
  19. const n = polymerType.length;
  20. const elements = OrderedSet.ofBounds(0, model.atomicConformation.atomId.rowCount) as OrderedSet<ElementIndex>;
  21. const polymerIt = SortedRanges.transientSegments(model.atomicRanges.polymerRanges, elements);
  22. const residueIt = Segmentation.transientSegments(model.atomicHierarchy.residueAtomSegments, elements);
  23. const centers = new Float32Array(n * 3);
  24. const axes = new Float32Array(n * 3);
  25. let i = 0;
  26. let j = -1;
  27. let s = -1;
  28. const a1 = Vec3();
  29. const a2 = Vec3();
  30. const a3 = Vec3();
  31. const a4 = Vec3();
  32. const r12 = Vec3();
  33. const r23 = Vec3();
  34. const r34 = Vec3();
  35. const v1 = Vec3();
  36. const v2 = Vec3();
  37. const vt = Vec3();
  38. const diff13 = Vec3();
  39. const diff24 = Vec3();
  40. const axis = Vec3();
  41. const prevAxis = Vec3();
  42. while (polymerIt.hasNext) {
  43. const ps = polymerIt.move();
  44. residueIt.setSegment(ps);
  45. i = -1;
  46. s = -1;
  47. while (residueIt.hasNext) {
  48. i += 1;
  49. const { index } = residueIt.move();
  50. if (i === 0) s = index;
  51. j = (index - 2);
  52. const j3 = j * 3;
  53. Vec3.copy(a1, a2);
  54. Vec3.copy(a2, a3);
  55. Vec3.copy(a3, a4);
  56. const eI = traceElementIndex[index];
  57. Vec3.set(a4, x[eI], y[eI], z[eI]);
  58. if (i < 3) continue;
  59. Vec3.sub(r12, a2, a1);
  60. Vec3.sub(r23, a3, a2);
  61. Vec3.sub(r34, a4, a3);
  62. Vec3.sub(diff13, r12, r23);
  63. Vec3.sub(diff24, r23, r34);
  64. Vec3.cross(axis, diff13, diff24);
  65. Vec3.normalize(axis, axis);
  66. Vec3.toArray(axis, axes, j3);
  67. const tmp = Math.cos(Vec3.angle(diff13, diff24));
  68. const diff13Length = Vec3.magnitude(diff13);
  69. const diff24Length = Vec3.magnitude(diff24);
  70. const r = (
  71. Math.sqrt(diff24Length * diff13Length) /
  72. // clamp, to avoid numerical instabilities for when
  73. // angle between diff13 and diff24 is close to 0
  74. Math.max(2.0, 2.0 * (1.0 - tmp))
  75. );
  76. Vec3.scale(v1, diff13, r / diff13Length);
  77. Vec3.sub(v1, a2, v1);
  78. Vec3.toArray(v1, centers, j3);
  79. Vec3.scale(v2, diff24, r / diff24Length);
  80. Vec3.sub(v2, a3, v2);
  81. Vec3.toArray(v2, centers, j3 + 3);
  82. Vec3.copy(prevAxis, axis);
  83. }
  84. // calc axis as dir of second and third center pos
  85. // project first trace atom onto axis to get first center pos
  86. const s3 = s * 3;
  87. Vec3.fromArray(v1, centers, s3 + 3);
  88. Vec3.fromArray(v2, centers, s3 + 6);
  89. Vec3.normalize(axis, Vec3.sub(axis, v1, v2));
  90. const sI = traceElementIndex[s];
  91. Vec3.set(a1, x[sI], y[sI], z[sI]);
  92. Vec3.copy(vt, a1);
  93. Vec3.projectPointOnVector(vt, vt, axis, v1);
  94. Vec3.toArray(vt, centers, s3);
  95. // calc axis as dir of n-1 and n-2 center pos
  96. // project last traceAtom onto axis to get last center pos
  97. const e = j + 2;
  98. const e3 = e * 3;
  99. Vec3.fromArray(v1, centers, e3 - 3);
  100. Vec3.fromArray(v2, centers, e3 - 6);
  101. Vec3.normalize(axis, Vec3.sub(axis, v1, v2));
  102. const eI = traceElementIndex[e];
  103. Vec3.set(a1, x[eI], y[eI], z[eI]);
  104. Vec3.copy(vt, a1);
  105. Vec3.projectPointOnVector(vt, vt, axis, v1);
  106. Vec3.toArray(vt, centers, e3);
  107. }
  108. return {
  109. centers
  110. };
  111. }