/* This file is part of wgrib2.
* aec_pk.c
* 6/2016 copyright DWD, under GNU GPL
* 6/2016 cleanup, optimizations Wesley Ebisuzaki
*
* wgrib2 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.
*
* wgrib2 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 wgrib2. If not, see .
*
*/
#include
#include
#include
#include
#include
#include
#include "grb2.h"
#include "wgrib2.h"
#include "fnlist.h"
#ifdef USE_AEC
#include
int aec_grib_out(unsigned char ** sec, float *data, unsigned int ndata, int use_scale,
int dec_scale, int bin_scale, int wanted_bits, int max_bits, struct seq_file *out){
int err, status;
unsigned char *sec0, *sec1, *sec2 , *sec3, *sec4, *sec5, *sec6, *sec7;
unsigned int i, j, n_defined, encodedLength, nbytes;
uint32_t ccsds_flags = 0;
uint32_t ccsds_block_size = 32; /* default value */
uint32_t ccsds_rsi = 128;
float min_val, max_val;
double ref, fmin, frange, scale, dec_factor;
int nbits, ii;
struct aec_stream strm;
unsigned char *inbuffer;
/* printf("aec_grib_out: use_scale = %d dec_scale = %d bin_scale = %d wanted_bits = %d max_bits = %d " ,
use_scale, dec_scale, bin_scale, wanted_bits, max_bits ); */
/* set default flags, TODO pass flags from template */
ccsds_flags = AEC_DATA_MSB | AEC_DATA_PREPROCESS | AEC_DATA_3BYTE;
inbuffer = NULL;
/* required passed sections */
sec0 = sec[0];
sec1 = sec[1];
sec2 = sec[2];
sec3 = sec[3];
sec4 = sec[4];
/* make a sections 5-7 */
n_defined = ndata;
sec6 = mk_bms(data, &n_defined); // make bitmap section, eliminate undefined grid values
min_max_array_all_defined(data, n_defined, &min_val, &max_val);
dec_factor = 1.0;
if (use_scale == 0) {
/* ecmwf style */
fmin = min_val;
frange = max_val - fmin;
ref = fmin;
dec_scale = 0;
if (frange != 0.0) {
frexp(frange, &ii);
bin_scale = ii - wanted_bits;
nbits = wanted_bits;
scale = ldexp(1.0, -bin_scale);
frange = floor((max_val-fmin)*scale + 0.5);
frexp(frange, &ii);
if (ii != nbits) bin_scale++;
}
else {
bin_scale = nbits = 0;
scale = 1;
}
}
else {
if (dec_scale) {
dec_factor = Int_Power(10.0, -dec_scale);
min_val *= dec_factor;
max_val *= dec_factor;
#pragma omp parallel for private(j)
for (j = 0; j < n_defined; j++) {
data[j] *= dec_factor;
}
}
ref = min_val;
scale = ldexp(1.0, -bin_scale);
// ii = (int) ( (max_val - ref)*scale + 0.5);
// frange = (double) ii;
frange = floor( (max_val - ref)*scale + 0.5);
frexp(frange, &nbits);
if (nbits > max_bits) {
bin_scale += (nbits - max_bits);
nbits = max_bits;
}
}
if (bin_scale) {
scale = ldexp(1.0, -bin_scale);
#pragma omp parallel for private(j)
for (j = 0; j < n_defined; j++) {
data[j] = (data[j] - ref)*scale;
}
}
else {
#pragma omp parallel for private(j)
for (j = 0; j < n_defined; j++) {
data[j] = data[j] - ref;
}
}
if (nbits > 0 && n_defined > 0) {
nbytes = (nbits + 7) / 8;
size_t inbuflen = nbytes * (size_t) n_defined;
inbuffer = (unsigned char*) malloc(inbuflen);
if (inbuffer == NULL) fatal_error("aes_pk: memory allocation","");
unsigned long unsigned_val;
#pragma omp parallel for private(i, unsigned_val, j)
for (i=0; i < n_defined; i++){
unsigned_val = (unsigned long) floor(data[i]+0.5);
unsigned_val = unsigned_val > 0 ? unsigned_val : 0; // should not be necessary but ..
for (j = 0; j < nbytes; j++) {
inbuffer[nbytes - 1 - j + i*nbytes] = (unsigned char) (unsigned_val & 255);
unsigned_val = unsigned_val >> 8;
}
}
size_t outbuflen = 10240 + nbytes * (size_t) n_defined;
sec7 = (unsigned char *) malloc(outbuflen + 5);
if (sec7 == NULL) fatal_error("aes_pk: memory allocation","");
strm.flags = ccsds_flags;
strm.bits_per_sample = nbits;
strm.block_size = ccsds_block_size;
strm.rsi = ccsds_rsi;
strm.next_out = sec7 + 5;
strm.avail_out = outbuflen;
strm.next_in = inbuffer;
strm.avail_in = inbuflen;
/* printf("*** Packing with AEC flags: %d bits per sample: %d block size: %d rsi: %d \n", strm.flags, strm.bits_per_sample, strm.block_size, strm.rsi ); */
if((err = aec_buffer_encode(&strm)) != AEC_OK) fatal_error_i("aec_buffer_encode %d", err);
/* printf("*** after aec_buffer_encode() of %d bytes input, strm.avail_in: %d strm.total_in: %d\n" , inbuflen, strm.avail_in, strm.total_in); */
encodedLength = strm.total_out;
}
else {
ref = min_val / dec_factor;
bin_scale = dec_scale = 0;
encodedLength = 0;
sec7 = (unsigned char *) malloc(5);
if (sec7 == NULL) fatal_error("aes_pk: memory allocation","");
}
size_t sec5size = 25;
sec5 = (unsigned char *) malloc(sec5size * sizeof(unsigned char));
if (sec5 == NULL) fatal_error("aes_pk: memory allocation","");
uint_char(sec5size * sizeof (unsigned char), sec5);
sec5[4] = 5; // section 5
uint_char(n_defined, sec5+5); // number of points
uint2_char(42,sec5+9); // data template 42 - AEC
flt2ieee(ref,sec5+11); // reference value
int2_char(bin_scale,sec5+15); // binary scaling
int2_char(-dec_scale,sec5+17); // decimal scaling
sec5[19] = nbits;
sec5[20] = 0; // 0 - float 1=int
sec5[21] = ccsds_flags;
sec5[22] = ccsds_block_size;
uint2_char((unsigned int) ccsds_rsi, sec5+23);
uint_char(encodedLength+5, sec7);
sec7[4] = 7; // section 7
status = wrt_sec(sec0, sec1, sec2, sec3, sec4, sec5, sec6, sec7, out);
free(sec5);
free(sec6);
free(sec7);
if(inbuffer) free(inbuffer);
return status;
}
#endif