diff --git a/src/mol-io/reader/ccp4/parser.ts b/src/mol-io/reader/ccp4/parser.ts index 629303b84d2858f57fc18d19b4550f274176c228..087b7ffc0711d5c37e63c89365ff138b341a981c 100644 --- a/src/mol-io/reader/ccp4/parser.ts +++ b/src/mol-io/reader/ccp4/parser.ts @@ -109,9 +109,7 @@ async function parseInternal(file: FileHandle, ctx: RuntimeContext): Promise<Res } export function parse(file: FileHandle) { - return Task.create<Result<Schema.Ccp4File>>('Parse CCP4', async ctx => { - return await parseInternal(file, ctx); - }); + return Task.create<Result<Schema.Ccp4File>>('Parse CCP4', ctx => parseInternal(file, ctx)); } export default parse; \ No newline at end of file diff --git a/src/mol-math/linear-algebra/tensor.ts b/src/mol-math/linear-algebra/tensor.ts index f1936a505f3d215ddc8edb9e12736e3f088cf162..3dccac7e1413476a68194042620dde4affaf387e 100644 --- a/src/mol-math/linear-algebra/tensor.ts +++ b/src/mol-math/linear-algebra/tensor.ts @@ -212,15 +212,21 @@ export namespace Tensor { return ret; } - export function getCanonicalAxisIndicesFastToSlow(order: number[]) { + function reorder(xs: number[], indices: number[]) { + const ret: number[] = []; + for (let i = 0; i < xs.length; i++) ret[i] = xs[indices[i]]; + return ret; + } + + export function convertToCanonicalAxisIndicesFastToSlow(order: number[]) { const indices = new Int32Array(order.length) as any as number[]; for (let i = 0; i < order.length; i++) indices[order[i]] = i; - return indices; + return (xs: number[]) => reorder(xs, indices); } - export function getCanonicalAxisIndicesSlowToFast(order: number[]) { + export function convertToCanonicalAxisIndicesSlowToFast(order: number[]) { const indices = new Int32Array(order.length) as any as number[]; for (let i = 0; i < order.length; i++) indices[order[order.length - i - 1]] = i; - return indices; + return (xs: number[]) => reorder(xs, indices); } } \ No newline at end of file diff --git a/src/mol-model/volume/formats/ccp4.ts b/src/mol-model/volume/formats/ccp4.ts index bed2de43b102abfeeb99e260d4e2c3497a16dab2..eaa685c1eebd53312011f299bded0c7081b686a4 100644 --- a/src/mol-model/volume/formats/ccp4.ts +++ b/src/mol-model/volume/formats/ccp4.ts @@ -32,21 +32,42 @@ function volumeFromCcp4(source: Ccp4File): Task<VolumeData> { const cell = SpacegroupCell.create( header.ISPG, Vec3.create(header.xLength, header.yLength, header.zLength), - Vec3.create(degToRad(header.alpha), degToRad(header.beta), degToRad(header.gamma) - )) + Vec3.create(degToRad(header.alpha), degToRad(header.beta), degToRad(header.gamma)) + ); - const origin = Vec3.create(header.originX, header.originY, header.originZ) - const dimensions = Vec3.create(header.NX, header.NY, header.NZ) - const axisOrder = Vec3.create(header.MAPC - 1, header.MAPR - 1, header.MAPS - 1) + const axis_order_fast_to_slow = Vec3.create(header.MAPC - 1, header.MAPR - 1, header.MAPS - 1); + const normalizeOrder = Tensor.convertToCanonicalAxisIndicesFastToSlow(axis_order_fast_to_slow); - const space = Tensor.Space(dimensions, axisOrder, header.MODE === 0 ? Int8Array : Float32Array); + const grid = [header.NX, header.NY, header.NZ]; + const extent = normalizeOrder([header.NC, header.NR, header.NS]); + + const gridOrigin: number[] = normalizeOrder([header.NCSTART, header.NRSTART, header.NSSTART]); + + // TODO: this is code from LiteMol, but not sure about the part based on originXYZ. The + // if (header.originX === 0.0 && header.originY === 0.0 && header.originZ === 0.0) { + // gridOrigin = normalizeOrder([header.NCSTART, header.NRSTART, header.NSSTART]); + // } else { + // // Use ORIGIN records rather than old n[xyz]start records + // // http://www2.mrc-lmb.cam.ac.uk/image2000.html + // // XXX the ORIGIN field is only used by the EM community, and + // // has undefined meaning for non-orthogonal maps and/or + // // non-cubic voxels, etc. + // gridOrigin = [header.originX, header.originY, header.originZ]; + // } + + const origin_frac = Vec3.create(gridOrigin[0] / grid[0], gridOrigin[1] / grid[1], gridOrigin[2] / grid[2]); + const dimensions_frac = Vec3.create(extent[0] / grid[0], extent[1] / grid[1], extent[2] / grid[2]); + + const space = Tensor.Space(extent, Tensor.invertAxisOrder(axis_order_fast_to_slow), header.MODE === 0 ? Int8Array : Float32Array); const data = Tensor.create(space, Tensor.Data1(values)); // TODO Calculate stats? When to trust header data? + // Min/max/mean are reliable (based on LiteMol/DensityServer usage) + // These, however, calculate sigma, so no data on that. return { cell, - fractionalBox: Box3D.create(origin, Vec3.add(Vec3.zero(), origin, dimensions)), + fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)), data, dataStats: { min: header.AMIN, diff --git a/src/mol-model/volume/formats/density-server.ts b/src/mol-model/volume/formats/density-server.ts index 10f3609bccf17d6a8ea92896524a4472c3a010bc..c01282e8e9d69ebd0cb24e35fef3730da9b0f337 100644 --- a/src/mol-model/volume/formats/density-server.ts +++ b/src/mol-model/volume/formats/density-server.ts @@ -10,10 +10,6 @@ import { Task } from 'mol-task'; import { SpacegroupCell, Box3D } from 'mol-math/geometry'; import { Tensor, Vec3 } from 'mol-math/linear-algebra'; -function normalizeOrder(v: number[], indices: number[]) { - return Vec3.create(v[indices[0]], v[indices[1]], v[indices[2]]) -} - function parseDensityServerData(source: DensityServer_Data_Database): Task<VolumeData> { return Task.create<VolumeData>('Parse Volume Data', async ctx => { const { volume_data_3d_info: info, volume_data_3d: values } = source; @@ -25,17 +21,17 @@ function parseDensityServerData(source: DensityServer_Data_Database): Task<Volum const axis_order_fast_to_slow = info.axis_order.value(0); - const indices = Tensor.getCanonicalAxisIndicesFastToSlow(axis_order_fast_to_slow); + const normalizeOrder = Tensor.convertToCanonicalAxisIndicesFastToSlow(axis_order_fast_to_slow); // sample count is in "axis order" and needs to be reordered - const sample_count = normalizeOrder(info.sample_count.value(0), indices); + const sample_count = normalizeOrder(info.sample_count.value(0)); const tensorSpace = Tensor.Space(sample_count, Tensor.invertAxisOrder(axis_order_fast_to_slow), Float32Array); const data = Tensor.create(tensorSpace, Tensor.Data1(values.values.toArray({ array: Float32Array }))); // origin and dimensions are in "axis order" and need to be reordered - const origin = normalizeOrder(info.origin.value(0), indices) - const dimensions = normalizeOrder(info.dimensions.value(0), indices); + const origin = Vec3.ofArray(normalizeOrder(info.origin.value(0))) + const dimensions = Vec3.ofArray(normalizeOrder(info.dimensions.value(0))); return { cell,