ccp4.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { VolumeData } from '../data'
  7. import { Task } from 'mol-task';
  8. import { SpacegroupCell, Box3D } from 'mol-math/geometry';
  9. import { Tensor, Vec3 } from 'mol-math/linear-algebra';
  10. import { Ccp4File } from 'mol-io/reader/ccp4/schema';
  11. import { degToRad } from 'mol-math/misc';
  12. function volumeFromCcp4(source: Ccp4File, params?: { voxelSize?: Vec3 }): Task<VolumeData> {
  13. return Task.create<VolumeData>('Parse Volume Data', async ctx => {
  14. const { header, values } = source;
  15. const size = Vec3.create(header.xLength, header.yLength, header.zLength)
  16. if (params && params.voxelSize) Vec3.mul(size, size, params.voxelSize)
  17. const angles = Vec3.create(degToRad(header.alpha), degToRad(header.beta), degToRad(header.gamma))
  18. const cell = SpacegroupCell.create(header.ISPG || 'P 1', size, angles);
  19. const axis_order_fast_to_slow = Vec3.create(header.MAPC - 1, header.MAPR - 1, header.MAPS - 1);
  20. const normalizeOrder = Tensor.convertToCanonicalAxisIndicesFastToSlow(axis_order_fast_to_slow);
  21. const grid = [header.NX, header.NY, header.NZ];
  22. const extent = normalizeOrder([header.NC, header.NR, header.NS]);
  23. let gridOrigin: number[]
  24. if (header.originX === 0.0 && header.originY === 0.0 && header.originZ === 0.0) {
  25. gridOrigin = normalizeOrder([header.NCSTART, header.NRSTART, header.NSSTART]);
  26. } else {
  27. // When available (e.g. in MRC files) use ORIGIN records instead of N[CRS]START
  28. gridOrigin = [header.originX, header.originY, header.originZ];
  29. }
  30. const origin_frac = Vec3.create(gridOrigin[0] / grid[0], gridOrigin[1] / grid[1], gridOrigin[2] / grid[2]);
  31. const dimensions_frac = Vec3.create(extent[0] / grid[0], extent[1] / grid[1], extent[2] / grid[2]);
  32. const space = Tensor.Space(extent, Tensor.invertAxisOrder(axis_order_fast_to_slow), header.MODE === 0 ? Int8Array : Float32Array);
  33. const data = Tensor.create(space, Tensor.Data1(values));
  34. // TODO Calculate stats? When to trust header data?
  35. // Min/max/mean are reliable (based on LiteMol/DensityServer usage)
  36. // These, however, calculate sigma, so no data on that.
  37. return {
  38. cell,
  39. fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)),
  40. data,
  41. dataStats: {
  42. min: header.AMIN,
  43. max: header.AMAX,
  44. mean: header.AMEAN,
  45. sigma: header.ARMS
  46. }
  47. };
  48. });
  49. }
  50. export { volumeFromCcp4 }