UNPKG

molstar

Version:

A comprehensive macromolecular library.

267 lines 11.6 kB
/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * Taken/adapted from DensityServer (https://github.com/dsehnal/DensityServer) * * @author David Sehnal <david.sehnal@gmail.com> */ import { __awaiter, __generator } from "tslib"; import * as Data from './data-model'; import * as File from '../common/file'; import * as Downsampling from './downsampling'; import * as Writer from './writer'; import * as DataFormat from '../common/data-format'; import { getElementByteSize, createTypedArray } from '../../../mol-io/common/typed-array'; import { SimpleBuffer } from '../../../mol-io/common/simple-buffer'; import { fileHandleFromDescriptor } from '../../common/file-handle'; export function createContext(filename, channels, blockSize, isPeriodic) { return __awaiter(this, void 0, void 0, function () { var _a, extent, valueType, grid, origin, samplingCounts, cubeBuffer, litteEndianCubeBuffer, ctx, _b, byteOffset, _i, _c, s; var _d; return __generator(this, function (_e) { switch (_e.label) { case 0: _a = channels[0].data.header, extent = _a.extent, valueType = _a.valueType, grid = _a.grid, origin = _a.origin; samplingCounts = getSamplingCounts(extent, blockSize); cubeBuffer = Buffer.from(new ArrayBuffer(channels.length * blockSize * blockSize * blockSize * getElementByteSize(valueType))); litteEndianCubeBuffer = SimpleBuffer.IsNativeEndianLittle ? cubeBuffer : Buffer.from(new ArrayBuffer(channels.length * blockSize * blockSize * blockSize * getElementByteSize(valueType))); // The data can be periodic iff the extent is the same as the grid and origin is 0. if (grid.some(function (v, i) { return v !== extent[i]; }) || origin.some(function (v) { return v !== 0; })) { isPeriodic = false; } _d = {}; _b = fileHandleFromDescriptor; return [4 /*yield*/, File.createFile(filename)]; case 1: ctx = (_d.file = _b.apply(void 0, [_e.sent(), filename]), _d.isPeriodic = isPeriodic, _d.channels = channels, _d.valueType = valueType, _d.blockSize = blockSize, _d.cubeBuffer = cubeBuffer, _d.litteEndianCubeBuffer = litteEndianCubeBuffer, _d.kernel = { size: 5, coefficients: [1, 4, 6, 4, 1], coefficientSum: 16 }, _d.sampling = samplingCounts.map(function (__, i) { return createSampling(i, valueType, channels.length, samplingCounts, blockSize); }), _d.dataByteOffset = 0, _d.totalByteSize = 0, _d.progress = { current: 0, max: 0 }, _d); byteOffset = 0; for (_i = 0, _c = ctx.sampling; _i < _c.length; _i++) { s = _c[_i]; // Max progress = total number of blocks that need to be written. ctx.progress.max += Data.samplingBlockCount(s, blockSize); s.byteOffset = byteOffset; byteOffset += s.byteSize; } ctx.dataByteOffset = 4 + DataFormat.encodeHeader(Data.createHeader(ctx)).byteLength; ctx.totalByteSize = ctx.dataByteOffset + byteOffset; return [2 /*return*/, ctx]; } }); }); } export function processData(ctx) { return __awaiter(this, void 0, void 0, function () { var channel, _i, _a, src; return __generator(this, function (_b) { switch (_b.label) { case 0: channel = ctx.channels[0]; _b.label = 1; case 1: if (!!channel.data.slices.isFinished) return [3 /*break*/, 7]; _i = 0, _a = ctx.channels; _b.label = 2; case 2: if (!(_i < _a.length)) return [3 /*break*/, 5]; src = _a[_i]; return [4 /*yield*/, src.provider.readSlices(src.data)]; case 3: _b.sent(); _b.label = 4; case 4: _i++; return [3 /*break*/, 2]; case 5: return [4 /*yield*/, processSlices(ctx)]; case 6: _b.sent(); return [3 /*break*/, 1]; case 7: return [2 /*return*/]; } }); }); } /** Determine the suitable sampling rates for the input data */ function getSamplingCounts(baseSampleCount, blockSize) { var ret = [baseSampleCount]; var prev = baseSampleCount; var hasSingleBoxSampling = false; while (true) { var next = [0, 0, 0]; var max = 0; for (var i = 0; i < 3; i++) { var s = Math.floor((prev[i] + 1) / 2); if (s < 2) return ret; if (s > max) max = s; next[i] = s; } // no point in downsampling below the block size. if (max < blockSize) { if (hasSingleBoxSampling) return ret; hasSingleBoxSampling = true; } ret.push(next); prev = next; } } function createBlockBuffer(sampleCount, blockSize, valueType, numChannels) { var values = []; for (var i = 0; i < numChannels; i++) values[i] = createTypedArray(valueType, sampleCount[0] * sampleCount[1] * blockSize); return { values: values, buffers: values.map(function (xs) { return Buffer.from(xs.buffer); }), slicesWritten: 0 }; } function createDownsamplingBuffer(valueType, sourceSampleCount, targetSampleCount, numChannels) { var ret = []; for (var i = 0; i < numChannels; i++) { ret[ret.length] = { downsampleH: createTypedArray(valueType, sourceSampleCount[1] * targetSampleCount[0]), downsampleHK: createTypedArray(valueType, 5 * targetSampleCount[0] * targetSampleCount[1]), slicesWritten: 0, startSliceIndex: 0 }; } return ret; } function createSampling(index, valueType, numChannels, sampleCounts, blockSize) { var sampleCount = sampleCounts[index]; var valuesInfo = []; for (var i = 0; i < numChannels; i++) { valuesInfo[valuesInfo.length] = { sum: 0.0, sqSum: 0.0, max: Number.NEGATIVE_INFINITY, min: Number.POSITIVE_INFINITY }; } return { rate: 1 << index, sampleCount: sampleCount, blocks: createBlockBuffer(sampleCount, blockSize, valueType, numChannels), valuesInfo: valuesInfo, downsampling: index < sampleCounts.length - 1 ? createDownsamplingBuffer(valueType, sampleCount, sampleCounts[index + 1], numChannels) : void 0, byteOffset: 0, byteSize: numChannels * sampleCount[0] * sampleCount[1] * sampleCount[2] * getElementByteSize(valueType), writeByteOffset: 0 }; } function copyLayer(ctx, sliceIndex) { var channels = ctx.channels; var _a = ctx.sampling[0], blocks = _a.blocks, sampleCount = _a.sampleCount; var size = sampleCount[0] * sampleCount[1]; var srcOffset = sliceIndex * size; var targetOffset = blocks.slicesWritten * size; for (var channelIndex = 0; channelIndex < channels.length; channelIndex++) { var src = channels[channelIndex].data.slices.values; var target = blocks.values[channelIndex]; for (var i = 0; i < size; i++) { var v = src[srcOffset + i]; target[targetOffset + i] = v; } } blocks.slicesWritten++; } function updateValuesInfo(sampling) { var blocks = sampling.blocks, sampleCount = sampling.sampleCount; var size = blocks.slicesWritten * sampleCount[0] * sampleCount[1]; for (var channelIndex = 0; channelIndex < blocks.values.length; channelIndex++) { var values = blocks.values[channelIndex]; var valuesInfo = sampling.valuesInfo[channelIndex]; var sum = valuesInfo.sum, sqSum = valuesInfo.sqSum, max = valuesInfo.max, min = valuesInfo.min; for (var i = 0; i < size; i++) { var v = values[i]; sum += v; sqSum += v * v; if (v > max) max = v; else if (v < min) min = v; } valuesInfo.sum = sum; valuesInfo.sqSum = sqSum; valuesInfo.max = max; valuesInfo.min = min; } } function shouldSamplingBeWritten(sampling, blockSize, isDataFinished) { if (isDataFinished) return sampling.blocks.slicesWritten > 0; return sampling.blocks.slicesWritten >= blockSize; } function writeBlocks(ctx, isDataFinished) { return __awaiter(this, void 0, void 0, function () { var _i, _a, s; return __generator(this, function (_b) { switch (_b.label) { case 0: _i = 0, _a = ctx.sampling; _b.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 4]; s = _a[_i]; if (!shouldSamplingBeWritten(s, ctx.blockSize, isDataFinished)) return [3 /*break*/, 3]; updateValuesInfo(s); return [4 /*yield*/, Writer.writeBlockLayer(ctx, s)]; case 2: _b.sent(); _b.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); } function processSlices(ctx) { return __awaiter(this, void 0, void 0, function () { var channel, sliceCount, i, isDataFinished; return __generator(this, function (_a) { switch (_a.label) { case 0: channel = ctx.channels[0]; sliceCount = channel.data.slices.sliceCount; i = 0; _a.label = 1; case 1: if (!(i < sliceCount)) return [3 /*break*/, 5]; copyLayer(ctx, i); Downsampling.downsampleLayer(ctx); return [4 /*yield*/, writeBlocks(ctx, false)]; case 2: _a.sent(); isDataFinished = i === sliceCount - 1 && channel.data.slices.isFinished; if (!isDataFinished) return [3 /*break*/, 4]; Downsampling.finalize(ctx); return [4 /*yield*/, writeBlocks(ctx, true)]; case 3: _a.sent(); _a.label = 4; case 4: i++; return [3 /*break*/, 1]; case 5: return [2 /*return*/]; } }); }); } //# sourceMappingURL=sampling.js.map