orbitals.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * Inspired by https://github.com/dgasmith/gau2grid.
  5. *
  6. * @author David Sehnal <david.sehnal@gmail.com>
  7. */
  8. import { sortArray } from '../../mol-data/util';
  9. import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
  10. import { WebGLContext } from '../../mol-gl/webgl/context';
  11. import { Task } from '../../mol-task';
  12. import { sphericalCollocation } from './collocation';
  13. import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
  14. import { gpuComputeAlphaOrbitalsGridValues } from './gpu/compute';
  15. // setDebugMode(true);
  16. export function createSphericalCollocationGrid(
  17. params: CubeGridComputationParams, orbital: AlphaOrbital, webgl?: WebGLContext
  18. ): Task<CubeGrid> {
  19. return Task.create('Spherical Collocation Grid', async (ctx) => {
  20. const cubeGrid = initCubeGrid(params);
  21. let matrix: Float32Array;
  22. if (canComputeGrid3dOnGPU(webgl)) {
  23. // console.time('gpu');
  24. matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl!, cubeGrid, orbital);
  25. // console.timeEnd('gpu');
  26. } else {
  27. // console.time('cpu');
  28. matrix = await sphericalCollocation(cubeGrid, orbital, ctx);
  29. // console.timeEnd('cpu');
  30. }
  31. const grid = createGrid(cubeGrid, matrix, [0, 1, 2]);
  32. let isovalues: { negative?: number, positive?: number } | undefined;
  33. if (!params.doNotComputeIsovalues) {
  34. isovalues = computeOrbitalIsocontourValues(matrix, 0.85);
  35. }
  36. return { grid, isovalues };
  37. });
  38. }
  39. export function computeOrbitalIsocontourValues(input: Float32Array, cumulativeThreshold: number) {
  40. let weightSum = 0;
  41. for (let i = 0, _i = input.length; i < _i; i++) {
  42. const v = input[i];
  43. const w = v * v;
  44. weightSum += w;
  45. }
  46. const avgWeight = weightSum / input.length;
  47. let minWeight = 3 * avgWeight;
  48. // do not try to identify isovalues for degenerate data
  49. // e.g. all values are almost same
  50. if (Math.abs(avgWeight - input[0] * input[0]) < 1e-5) {
  51. return { negative: void 0, positive: void 0 };
  52. }
  53. let size = 0;
  54. while (true) {
  55. let csum = 0;
  56. size = 0;
  57. for (let i = 0, _i = input.length; i < _i; i++) {
  58. const v = input[i];
  59. const w = v * v;
  60. if (w >= minWeight) {
  61. csum += w;
  62. size++;
  63. }
  64. }
  65. if (csum / weightSum > cumulativeThreshold) {
  66. break;
  67. }
  68. minWeight -= avgWeight;
  69. }
  70. const values = new Float32Array(size);
  71. const weights = new Float32Array(size);
  72. const indices = new Int32Array(size);
  73. let o = 0;
  74. for (let i = 0, _i = input.length; i < _i; i++) {
  75. const v = input[i];
  76. const w = v * v;
  77. if (w >= minWeight) {
  78. values[o] = v;
  79. weights[o] = w;
  80. indices[o] = o;
  81. o++;
  82. }
  83. }
  84. sortArray(
  85. indices,
  86. (indices, i, j) => weights[indices[j]] - weights[indices[i]]
  87. );
  88. let cweight = 0,
  89. cutoffIndex = 0;
  90. for (let i = 0; i < size; i++) {
  91. cweight += weights[indices[i]];
  92. if (cweight / weightSum >= cumulativeThreshold) {
  93. cutoffIndex = i;
  94. break;
  95. }
  96. }
  97. let positive = Number.POSITIVE_INFINITY,
  98. negative = Number.NEGATIVE_INFINITY;
  99. for (let i = 0; i < cutoffIndex; i++) {
  100. const v = values[indices[i]];
  101. if (v > 0) {
  102. if (v < positive) positive = v;
  103. } else if (v < 0) {
  104. if (v > negative) negative = v;
  105. }
  106. }
  107. return {
  108. negative: negative !== Number.NEGATIVE_INFINITY ? negative : void 0,
  109. positive: positive !== Number.POSITIVE_INFINITY ? positive : void 0,
  110. };
  111. }