NGL@1.0.0-beta.7 Home Manual Reference Source Gallery

src/align/superposition.js

  1. /**
  2. * @file Superposition
  3. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  4. * @private
  5. */
  6.  
  7. import { Debug, Log } from '../globals.js'
  8. import {
  9. Matrix, svd, meanRows, subRows, addRows, transpose,
  10. multiplyABt, invert3x3, multiply3x3, mat3x3determinant
  11. } from '../math/matrix-utils.js'
  12.  
  13. class Superposition {
  14. constructor (atoms1, atoms2) {
  15. // allocate & init data structures
  16.  
  17. var n1
  18. if (typeof atoms1.eachAtom === 'function') {
  19. n1 = atoms1.atomCount
  20. } else if (atoms1 instanceof Float32Array) {
  21. n1 = atoms1.length / 3
  22. }
  23.  
  24. var n2
  25. if (typeof atoms2.eachAtom === 'function') {
  26. n2 = atoms2.atomCount
  27. } else if (atoms1 instanceof Float32Array) {
  28. n2 = atoms2.length / 3
  29. }
  30.  
  31. var n = Math.min(n1, n2)
  32.  
  33. var coords1 = new Matrix(3, n)
  34. var coords2 = new Matrix(3, n)
  35.  
  36. this.coords1t = new Matrix(n, 3)
  37. this.coords2t = new Matrix(n, 3)
  38.  
  39. this.A = new Matrix(3, 3)
  40. this.W = new Matrix(1, 3)
  41. this.U = new Matrix(3, 3)
  42. this.V = new Matrix(3, 3)
  43. this.VH = new Matrix(3, 3)
  44. this.R = new Matrix(3, 3)
  45.  
  46. this.tmp = new Matrix(3, 3)
  47. this.c = new Matrix(3, 3)
  48. this.c.data.set([ 1, 0, 0, 0, 1, 0, 0, 0, -1 ])
  49.  
  50. // prep coords
  51.  
  52. this.prepCoords(atoms1, coords1, n)
  53. this.prepCoords(atoms2, coords2, n)
  54.  
  55. // superpose
  56.  
  57. this._superpose(coords1, coords2)
  58. }
  59.  
  60. _superpose (coords1, coords2) {
  61. this.mean1 = meanRows(coords1)
  62. this.mean2 = meanRows(coords2)
  63.  
  64. subRows(coords1, this.mean1)
  65. subRows(coords2, this.mean2)
  66.  
  67. transpose(this.coords1t, coords1)
  68. transpose(this.coords2t, coords2)
  69.  
  70. multiplyABt(this.A, this.coords2t, this.coords1t)
  71.  
  72. svd(this.A, this.W, this.U, this.V)
  73.  
  74. invert3x3(this.V, this.VH)
  75. multiply3x3(this.R, this.U, this.VH)
  76.  
  77. if (mat3x3determinant(this.R) < 0.0) {
  78. if (Debug) Log.log('R not a right handed system')
  79.  
  80. multiply3x3(this.tmp, this.c, this.VH)
  81. multiply3x3(this.R, this.U, this.tmp)
  82. }
  83. }
  84.  
  85. prepCoords (atoms, coords, n) {
  86. var i = 0
  87. var n3 = n * 3
  88. var cd = coords.data
  89.  
  90. if (typeof atoms.eachAtom === 'function') {
  91. atoms.eachAtom(function (a) {
  92. if (i < n3) {
  93. cd[ i + 0 ] = a.x
  94. cd[ i + 1 ] = a.y
  95. cd[ i + 2 ] = a.z
  96.  
  97. i += 3
  98. }
  99. })
  100. } else if (atoms instanceof Float32Array) {
  101. cd.set(atoms.subarray(0, n3))
  102. } else {
  103. Log.warn('prepCoords: input type unknown')
  104. }
  105. }
  106.  
  107. transform (atoms) {
  108. // allocate data structures
  109.  
  110. var n
  111. if (typeof atoms.eachAtom === 'function') {
  112. n = atoms.atomCount
  113. } else if (atoms instanceof Float32Array) {
  114. n = atoms.length / 3
  115. }
  116.  
  117. var coords = new Matrix(3, n)
  118. var tmp = new Matrix(n, 3)
  119.  
  120. // prep coords
  121.  
  122. this.prepCoords(atoms, coords, n)
  123.  
  124. // do transform
  125.  
  126. subRows(coords, this.mean1)
  127. multiplyABt(tmp, this.R, coords)
  128. transpose(coords, tmp)
  129. addRows(coords, this.mean2)
  130.  
  131. var i = 0
  132. var cd = coords.data
  133.  
  134. if (typeof atoms.eachAtom === 'function') {
  135. atoms.eachAtom(function (a) {
  136. a.x = cd[ i + 0 ]
  137. a.y = cd[ i + 1 ]
  138. a.z = cd[ i + 2 ]
  139.  
  140. i += 3
  141. })
  142. } else if (atoms instanceof Float32Array) {
  143. atoms.set(cd.subarray(0, n * 3))
  144. } else {
  145. Log.warn('transform: input type unknown')
  146. }
  147. }
  148. }
  149.  
  150. export default Superposition