util.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /**
  2. * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. * @author Ludovic Autin <ludovic.autin@gmail.com>
  6. */
  7. import { CIF } from '../../mol-io/reader/cif';
  8. import { parsePDB } from '../../mol-io/reader/pdb/parser';
  9. import { AssetManager, Asset } from '../../mol-util/assets';
  10. import { Structure } from '../../mol-model/structure';
  11. import { Vec3 } from '../../mol-math/linear-algebra';
  12. import { PluginContext } from '../../mol-plugin/context';
  13. export async function parseCif(plugin: PluginContext, data: string | Uint8Array) {
  14. const comp = CIF.parse(data);
  15. const parsed = await plugin.runTask(comp);
  16. if (parsed.isError) throw parsed;
  17. return parsed.result;
  18. }
  19. export async function parsePDBfile(plugin: PluginContext, data: string, id: string) {
  20. const comp = parsePDB(data, id);
  21. const parsed = await plugin.runTask(comp);
  22. if (parsed.isError) throw parsed;
  23. return parsed.result;
  24. }
  25. async function downloadCif(plugin: PluginContext, url: string, isBinary: boolean, assetManager: AssetManager) {
  26. const type = isBinary ? 'binary' : 'string';
  27. const asset = await plugin.runTask(assetManager.resolve(Asset.getUrlAsset(assetManager, url), type));
  28. return { cif: await parseCif(plugin, asset.data), asset };
  29. }
  30. async function downloadPDB(plugin: PluginContext, url: string, id: string, assetManager: AssetManager) {
  31. const asset = await assetManager.resolve(Asset.getUrlAsset(assetManager, url), 'string').run();
  32. return { pdb: await parsePDBfile(plugin, asset.data, id), asset };
  33. }
  34. export async function getFromPdb(plugin: PluginContext, pdbId: string, assetManager: AssetManager) {
  35. const { cif, asset } = await downloadCif(plugin, `https://models.rcsb.org/${pdbId}.bcif`, true, assetManager);
  36. return { mmcif: cif.blocks[0], asset };
  37. }
  38. export async function getFromOPM(plugin: PluginContext, pdbId: string, assetManager: AssetManager) {
  39. const asset = await plugin.runTask(assetManager.resolve(Asset.getUrlAsset(assetManager, `https://opm-assets.storage.googleapis.com/pdb/${pdbId.toLowerCase()}.pdb`), 'string'));
  40. return { pdb: await parsePDBfile(plugin, asset.data, pdbId), asset };
  41. }
  42. export async function getFromCellPackDB(plugin: PluginContext, id: string, baseUrl: string, assetManager: AssetManager) {
  43. if (id.toLowerCase().endsWith('.cif') || id.toLowerCase().endsWith('.bcif')) {
  44. const isBinary = id.toLowerCase().endsWith('.bcif');
  45. const { cif, asset } = await downloadCif(plugin, `${baseUrl}/other/${id}`, isBinary, assetManager);
  46. return { mmcif: cif.blocks[0], asset };
  47. } else {
  48. const name = id.endsWith('.pdb') ? id.substring(0, id.length - 4) : id;
  49. return await downloadPDB(plugin, `${baseUrl}/other/${name}.pdb`, name, assetManager);
  50. }
  51. }
  52. export type IngredientFiles = { [name: string]: Asset.File }
  53. export function getStructureMean(structure: Structure) {
  54. let xSum = 0, ySum = 0, zSum = 0;
  55. for (let i = 0, il = structure.units.length; i < il; ++i) {
  56. const unit = structure.units[i];
  57. const { elements } = unit;
  58. const { x, y, z } = unit.conformation;
  59. for (let j = 0, jl = elements.length; j < jl; ++j) {
  60. const eI = elements[j];
  61. xSum += x(eI);
  62. ySum += y(eI);
  63. zSum += z(eI);
  64. }
  65. }
  66. const { elementCount } = structure;
  67. return Vec3.create(xSum / elementCount, ySum / elementCount, zSum / elementCount);
  68. }
  69. export function getFloatValue(value: DataView, offset: number) {
  70. // if the last byte is a negative value (MSB is 1), the final
  71. // float should be too
  72. const negative = value.getInt8(offset + 2) >>> 31;
  73. // this is how the bytes are arranged in the byte array/DataView
  74. // buffer
  75. const [b0, b1, b2, exponent] = [
  76. // get first three bytes as unsigned since we only care
  77. // about the last 8 bits of 32-bit js number returned by
  78. // getUint8().
  79. // Should be the same as: getInt8(offset) & -1 >>> 24
  80. value.getUint8(offset),
  81. value.getUint8(offset + 1),
  82. value.getUint8(offset + 2),
  83. // get the last byte, which is the exponent, as a signed int
  84. // since it's already correct
  85. value.getInt8(offset + 3)
  86. ];
  87. let mantissa = b0 | (b1 << 8) | (b2 << 16);
  88. if (negative) {
  89. // need to set the most significant 8 bits to 1's since a js
  90. // number is 32 bits but our mantissa is only 24.
  91. mantissa |= 255 << 24;
  92. }
  93. return mantissa * Math.pow(10, exponent);
  94. }