data-format.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * Taken/adapted from DensityServer (https://github.com/dsehnal/DensityServer)
  5. *
  6. * @author David Sehnal <david.sehnal@gmail.com>
  7. */
  8. import * as Schema from './binary-schema'
  9. import { FileHandle } from 'mol-io/common/file-handle';
  10. import { TypedArrayValueType } from 'mol-io/common/typed-array';
  11. export interface Spacegroup {
  12. number: number,
  13. size: number[],
  14. angles: number[],
  15. /** Determine if the data should be treated as periodic or not. (e.g. X-ray = periodic, EM = not periodic) */
  16. isPeriodic: boolean,
  17. }
  18. export interface ValuesInfo {
  19. mean: number,
  20. sigma: number,
  21. min: number,
  22. max: number
  23. }
  24. export interface Sampling {
  25. byteOffset: number,
  26. /** How many values along each axis were collapsed into 1 */
  27. rate: number,
  28. valuesInfo: ValuesInfo[],
  29. /** Number of samples along each axis, in axisOrder */
  30. sampleCount: number[]
  31. }
  32. export interface Header {
  33. /** Format version number */
  34. formatVersion: string,
  35. /** Axis order from the slowest to fastest moving, same as in CCP4 */
  36. axisOrder: number[],
  37. /** Origin in fractional coordinates, in axisOrder */
  38. origin: number[],
  39. /** Dimensions in fractional coordinates, in axisOrder */
  40. dimensions: number[],
  41. spacegroup: Spacegroup,
  42. channels: string[],
  43. /** Determines the data type of the values */
  44. valueType: TypedArrayValueType,
  45. /** The value are stored in blockSize^3 cubes */
  46. blockSize: number,
  47. sampling: Sampling[]
  48. }
  49. namespace _schema {
  50. const { array, obj, int, bool, float, str } = Schema
  51. export const schema = obj<Header>([
  52. ['formatVersion', str],
  53. ['axisOrder', array(int)],
  54. ['origin', array(float)],
  55. ['dimensions', array(float)],
  56. ['spacegroup', obj<Spacegroup>([
  57. ['number', int],
  58. ['size', array(float)],
  59. ['angles', array(float)],
  60. ['isPeriodic', bool],
  61. ])],
  62. ['channels', array(str)],
  63. ['valueType', str],
  64. ['blockSize', int],
  65. ['sampling', array(obj<Sampling>([
  66. ['byteOffset', float],
  67. ['rate', int],
  68. ['valuesInfo', array(obj<ValuesInfo>([
  69. ['mean', float],
  70. ['sigma', float],
  71. ['min', float],
  72. ['max', float]
  73. ]))],
  74. ['sampleCount', array(int)]
  75. ]))]
  76. ]);
  77. }
  78. const headerSchema = _schema.schema;
  79. export function encodeHeader(header: Header) {
  80. return Schema.encode(headerSchema, header);
  81. }
  82. export async function readHeader(file: FileHandle): Promise<{ header: Header, dataOffset: number }> {
  83. let { buffer } = await file.readBuffer(0, 4 * 4096);
  84. const headerSize = buffer.readInt32LE(0);
  85. if (headerSize > buffer.byteLength - 4) {
  86. buffer = (await file.readBuffer(0, headerSize + 4)).buffer;
  87. }
  88. const header = Schema.decode<Header>(headerSchema, buffer, 4);
  89. return { header, dataOffset: headerSize + 4 };
  90. }