/* Copyright 2014-2016 Jan Huwald, Stephan Richter
This file is part of HRTC.
HRTC is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
HRTC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program (see file LICENSE). If not, see
. */
#include "common.hpp"
#include "compressor.hpp"
#include "decompressor.hpp"
#include "format.hpp"
const int chunkSize = 1024;
template
void compressionLoop(function*(void)> compressorFactory,
function reader,
TId numberOfTrajectories, int sourceFileHandle, int blockSize) {
Real *trajectoryData = new Real[numberOfTrajectories];
int block(blockSize);
CompressorState *compressor(nullptr);
while (reader(trajectoryData, numberOfTrajectories, sourceFileHandle)) {
if (block == blockSize) {
if (compressor) {
compressor->finish();
delete compressor;
}
compressor = compressorFactory();
block = 0;
}
compressor->addFrame(trajectoryData);
block++;
}
if (block)
compressor->finish();
if (compressor)
delete compressor;
cerr << "done at " << __LINE__ << endl;
}
double *foo = new double;
template
void decompressionLoop(function*(void)> decompressorFactory,
TId numberOfTrajectories, uint blockSize) {
Real *trajectoryData = new Real[numberOfTrajectories];
uint frameInBlock;
do {
frameInBlock = 0;
DecompressorState *decompressor = decompressorFactory();
while (decompressor->readFrame(trajectoryData)) {
frameInBlock++;
for (int i=0; i()->default_value("-"),
"source file name")
("dst", prog_options::value()->default_value("-"),
"destination file name")
("format", prog_options::value()->default_value("tsvfloat"),
"file format: hufloat, hudouble, tsvfloat, tsvdouble...")
("numtraj", prog_options::value(),
"number of trajectories (#particles * #dim)")
("bound", prog_options::value(),
"maximal (absolute) value of a trajectory")
("error", prog_options::value(),
"maximal deviation from trajectory (quantization + prediction)")
("qp-ratio", prog_options::value()->default_value(0.1),
"ratio (0..1) to split the error between quantization and prediction")
("blocksize", prog_options::value()->default_value(1024),
"frames per block")
("integer-encoding", prog_options::value()->default_value(14),
"code id used by integer encoding library")
;
prog_options::variables_map options; // this stores command line options
try {
prog_options::store(prog_options::parse_command_line(argc, argv, cmdOpts), options);
} catch (...) {
cerr << cmdOpts << endl;
exit(EXIT_FAILURE);
}
prog_options::notify(options);
assert(options.count("compress") + options.count("decompress") <= 1); // at least one of the two options is needed!
auto require = [&](string name) {
if (!options.count(name)) {
cerr << "--" << name << " missing\n\n" << cmdOpts << endl;
exit(EXIT_FAILURE);
}
return options[name];
};
TId numberOfTrajectories = require("numtraj").as();
// open I/O handles
int sourceFileHandle = 0; // 0 ≙ std in
{ auto name = require("src").as();
if (name != "-")
assert((sourceFileHandle = open(name.c_str(), O_RDONLY)) >= 0); }
int sinkFileHandle = 1; // 1 ≙ std out
{
auto name = require("dst").as();
if (name != "-") {
assert((sinkFileHandle = open(name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH)) >= 0);
}
}
// Split the error between quantization error (quantum/2) and
// prediction error (error). The total error is error + quantum/2;
double qpr = require("qp-ratio").as();
assert((qpr >= 0) && (qpr <= 1));
double error = require("error").as() * (1 - qpr);
double quantum = require("error").as() * qpr * 2;
double bound = require("bound").as();
int integerEncoder = require("integer-encoding").as();
/// execute (de)compression
if (options.count("decompress")) {
auto decompressorFactory = [&]() {
return new DecompressorState (numberOfTrajectories, quantum, chunkSize, integer_encoding::EncodingFactory::create(integerEncoder), [=](char* buf) -> ChunkSize {
ChunkSize chunkSize;
if ((read(sourceFileHandle, &chunkSize, sizeof(chunkSize))) == sizeof(chunkSize)) {
assert(read(sourceFileHandle, buf, chunkSize.compressed) == chunkSize.compressed);
}else{
chunkSize.compressed = 0, chunkSize.raw = 0;
}
return chunkSize;
});
};
decompressionLoop(decompressorFactory, numberOfTrajectories, options["blocksize"].as());
}else{
auto compressorFactory = [&]() {
return new CompressorState
(numberOfTrajectories, error, bound, quantum, chunkSize, integer_encoding::EncodingFactory::create(integerEncoder), [&](char* buf, ChunkSize chunkSize) {
assert(write(sinkFileHandle, &chunkSize, sizeof(chunkSize)) == sizeof(chunkSize));
assert(write(sinkFileHandle, buf, chunkSize.compressed) == chunkSize.compressed);
});
};
function format;
auto fmtString = options["format"].as();
if (fmtString == "hudouble") { format = readHubin; }
else { assert(false); }
compressionLoop(compressorFactory, format, numberOfTrajectories, sourceFileHandle, options["blocksize"].as());
}
return 0;
}