molstar
Version:
A comprehensive macromolecular library.
182 lines • 8.31 kB
JavaScript
/**
* 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 Format from './format';
import * as File from '../common/file';
import * as Data from './data-model';
import * as Sampling from './sampling';
import * as DataFormat from '../common/data-format';
export function pack(input, blockSizeInMB, isPeriodic, outputFilename, format) {
return __awaiter(this, void 0, void 0, function () {
var e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, create(outputFilename, input, blockSizeInMB, isPeriodic, format)];
case 1:
_a.sent();
return [3 /*break*/, 3];
case 2:
e_1 = _a.sent();
console.error('[Error] ' + e_1);
return [3 /*break*/, 3];
case 3: return [2 /*return*/];
}
});
});
}
function getTime() {
var t = process.hrtime();
return t[0] * 1000 + t[1] / 1000000;
}
function updateAllocationProgress(progress, progressDone) {
var old = (100 * progress.current / progress.max).toFixed(0);
progress.current += progressDone;
var $new = (100 * progress.current / progress.max).toFixed(0);
if (old !== $new) {
process.stdout.write("\rAllocating... " + $new + "%");
}
}
/**
* Pre allocate the disk space to be able to do "random" writes into the entire file.
*/
function allocateFile(ctx) {
return __awaiter(this, void 0, void 0, function () {
var totalByteSize, file, buffer, progress, written;
return __generator(this, function (_a) {
totalByteSize = ctx.totalByteSize, file = ctx.file;
buffer = Buffer.alloc(Math.min(totalByteSize, 8 * 1024 * 1024));
progress = { current: 0, max: Math.ceil(totalByteSize / buffer.byteLength) };
written = 0;
while (written < totalByteSize) {
written += file.writeBufferSync(written, buffer, Math.min(totalByteSize - written, buffer.byteLength));
updateAllocationProgress(progress, 1);
}
return [2 /*return*/];
});
});
}
function determineBlockSize(data, blockSizeInMB) {
var extent = data.header.extent;
var maxLayerSize = 1024 * 1024 * 1024;
var valueCount = extent[0] * extent[1];
if (valueCount * blockSizeInMB <= maxLayerSize)
return blockSizeInMB;
while (blockSizeInMB > 0) {
blockSizeInMB -= 4;
if (valueCount * blockSizeInMB <= maxLayerSize)
return blockSizeInMB;
}
throw new Error('Could not determine a valid block size.');
}
function writeHeader(ctx) {
return __awaiter(this, void 0, void 0, function () {
var header;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
header = DataFormat.encodeHeader(Data.createHeader(ctx));
return [4 /*yield*/, File.writeInt(ctx.file, header.byteLength, 0)];
case 1:
_a.sent();
return [4 /*yield*/, ctx.file.writeBuffer(4, header)];
case 2:
_a.sent();
return [2 /*return*/];
}
});
});
}
function create(filename, sourceDensities, sourceBlockSizeInMB, isPeriodic, format) {
return __awaiter(this, void 0, void 0, function () {
var startedTime, files, channels_3, _i, sourceDensities_1, s, _a, _b, isOk, blockSizeInMB, _c, channels_1, ch, context, _d, channels_2, s, time, _e, files_1, f;
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
startedTime = getTime();
if (sourceBlockSizeInMB % 4 !== 0 || sourceBlockSizeInMB < 4) {
throw Error('Block size must be a positive number divisible by 4.');
}
if (!sourceDensities.length) {
throw Error('Specify at least one source density.');
}
process.stdout.write("Initializing using " + format + " format...");
files = [];
_f.label = 1;
case 1:
_f.trys.push([1, , 10, 11]);
channels_3 = [];
_i = 0, sourceDensities_1 = sourceDensities;
_f.label = 2;
case 2:
if (!(_i < sourceDensities_1.length)) return [3 /*break*/, 5];
s = sourceDensities_1[_i];
_b = (_a = channels_3).push;
return [4 /*yield*/, Format.open(s.name, s.filename, format)];
case 3:
_b.apply(_a, [_f.sent()]);
_f.label = 4;
case 4:
_i++;
return [3 /*break*/, 2];
case 5:
isOk = channels_3.reduce(function (ok, s) { return ok && Format.compareHeaders(channels_3[0].data.header, s.data.header); }, true);
if (!isOk) {
throw new Error('Input file headers are not compatible (different grid, etc.).');
}
blockSizeInMB = determineBlockSize(channels_3[0].data, sourceBlockSizeInMB);
for (_c = 0, channels_1 = channels_3; _c < channels_1.length; _c++) {
ch = channels_1[_c];
Format.assignSliceBuffer(ch.data, blockSizeInMB);
}
return [4 /*yield*/, Sampling.createContext(filename, channels_3, blockSizeInMB, isPeriodic)];
case 6:
context = _f.sent();
for (_d = 0, channels_2 = channels_3; _d < channels_2.length; _d++) {
s = channels_2[_d];
files.push(s.data.file);
}
files.push(context.file);
process.stdout.write(' done.\n');
console.log("Block size: " + blockSizeInMB);
// Step 2: Allocate disk space.
process.stdout.write('Allocating... 0%');
return [4 /*yield*/, allocateFile(context)];
case 7:
_f.sent();
process.stdout.write('\rAllocating... done.\n');
// Step 3: Process and write the data
process.stdout.write('Writing data... 0%');
return [4 /*yield*/, Sampling.processData(context)];
case 8:
_f.sent();
process.stdout.write('\rWriting data... done.\n');
// Step 4: Write the header at the start of the file.
// The header is written last because the sigma/min/max values are computed
// during step 3.
process.stdout.write('Writing header... ');
return [4 /*yield*/, writeHeader(context)];
case 9:
_f.sent();
process.stdout.write('done.\n');
time = getTime() - startedTime;
console.log("[Done] " + time.toFixed(0) + "ms.");
return [3 /*break*/, 11];
case 10:
for (_e = 0, files_1 = files; _e < files_1.length; _e++) {
f = files_1[_e];
f.close();
}
return [7 /*endfinally*/];
case 11: return [2 /*return*/];
}
});
});
}
//# sourceMappingURL=main.js.map