/* 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"
extern "C" {
#include
}
template
tng_function_status typed_hrtc_compress(const tng_trajectory_t tng_data,
const int64_t n_frames,
const int64_t n_particles,
char **data,
int64_t *new_len) {
int64_t dimensions;
double bound = 0,error = 0,quantum = 0;
{// this block: read number of dimensions + read box shape to calculate bound
// this is done here, because tng_data_block_write does not know about
// these things and thus cannot pass it
char type;
union data_values **box_data = 0;
int64_t dummy,current_dimension;
tng_function_status stat=tng_data_get(tng_data,TNG_TRAJ_BOX_SHAPE,&box_data,&dummy,&dimensions,&type);
assert(stat == TNG_SUCCESS);
assert(dimensions>0);
double val = 0; // current dimension value in loop
for (current_dimension=0; current_dimension0);
bound = max(val,bound);
}
}
{ // this block: set error and quantum using precision from tng_environment
double precision;
tng_function_status stat = tng_compression_precision_get(tng_data,&precision);
assert(precision!=0);
quantum=1/precision;
assert(stat == TNG_SUCCESS);
error = quantum/2;
assert(error>0);
assert(quantum>0);
}
char* result = nullptr;
size_t result_size=sizeof(double); // for quantum
result=(char*) malloc(result_size); // allocate memory for one double
memcpy(result,&quantum,result_size); // copy double to result data
int integerEncoder = 5; // pareto optimal / good space-time tradeoff
int numberOfTrajectories=n_particles*dimensions;
CompressorState compressor(numberOfTrajectories,
error,
bound,
quantum,
1024 /* chunk size */,
integer_encoding::EncodingFactory::create(integerEncoder),
[&](char* buf, ChunkSize chunkSize) {
auto offset=result_size;
result_size+= sizeof(chunkSize) + chunkSize.compressed;
result = (char*) realloc(result,result_size);
// printf("chunksize: %d (raw) => %d (compressed), offset: %d\n",chunkSize.raw,chunkSize.compressed,offset);
memcpy((void*)(result+offset),(void*)&chunkSize,sizeof(chunkSize));
offset+=sizeof(chunkSize);
memcpy((void*)(result+offset),(void*)buf,chunkSize.compressed);
});
auto traj_data=(T*) *data;
for (int64_t frame_number=0;frame_number
tng_function_status typed_hrtc_uncompress(const tng_trajectory_t tng_data,
char **data) {
int64_t dimensions,number_of_frames,number_of_particles;
double bound = 0,error = 0,quantum = 0;
int integerEncoder = 5; // pareto optimal / good space-time tradeoff
{// this block: read number of dimensions + number of frames + box shape to calculate bound
char type;
union data_values **box_data = 0;
int64_t current_dimension;
tng_function_status stat=tng_data_get(tng_data,TNG_TRAJ_BOX_SHAPE,&box_data,&number_of_frames,&dimensions,&type);
assert(stat == TNG_SUCCESS);
assert(dimensions>0);
assert(number_of_frames>0);
double val = 0; // current dimension value in loop
for (current_dimension=0; current_dimension0);
bound = max(val,bound);
}
}
{ // this block: determine number of particles
tng_function_status stat = tng_num_molecules_get(tng_data, &number_of_particles);
assert(stat == TNG_SUCCESS);
assert(number_of_particles>0);
}
{ // this block: determine number of frames per frameset
tng_function_status stat = tng_num_frames_per_frame_set_get(tng_data, &number_of_frames);
assert(stat == TNG_SUCCESS);
assert(number_of_frames>0);
}
int number_of_trajectories=number_of_particles*dimensions;
auto src_buf = *data;
{ // this block: read quantum from data blob, set error
quantum = *((double*) src_buf); // reading quantum from tip of data blob
src_buf+=sizeof(double); // moving pointer ahead
error = quantum/2;
assert(error>0);
assert(quantum>0);
}
DecompressorState decompressor(number_of_trajectories,
quantum,
1024 /* chunk size */,
integer_encoding::EncodingFactory::create(integerEncoder),
[&](char* buf) -> ChunkSize {
ChunkSize chunkSize = *((ChunkSize*) src_buf);
src_buf += sizeof(chunkSize);
// printf("chunksize: %d (compressed) => %d (raw)\n",chunkSize.compressed,chunkSize.raw);
// printf("src_buf: %d\n",src_buf-*data);
memcpy(buf,src_buf,chunkSize.compressed);
src_buf += chunkSize.compressed;
return chunkSize;
});
auto result = (T*) malloc(number_of_frames * number_of_trajectories * sizeof(T));
auto result_pos = result;
for (int i=0; i(tng_data,n_frames,n_particles,data,new_len);
case TNG_FLOAT_DATA:
return typed_hrtc_compress(tng_data,n_frames,n_particles,data,new_len);
default:
return TNG_FAILURE;
}
}
/* decompression */
tng_function_status hrtc_uncompress(const tng_trajectory_t tng_data,
const char type,
char **data) {
switch (type){
case TNG_DOUBLE_DATA:
return typed_hrtc_uncompress(tng_data,data);
case TNG_FLOAT_DATA:
return typed_hrtc_uncompress(tng_data,data);
default:
return TNG_FAILURE;
}
}
void hrtc_version(){
cout << hrtc_version_string() << "\n";
}
}