ECC-261: Reduce packing error by optimizing scaling factor (Part 2)

This commit is contained in:
Shahram Najm 2016-11-15 17:16:20 +00:00
parent ea7ca7c180
commit 9acee6d01f
2 changed files with 1233 additions and 19 deletions

View File

@ -221,8 +221,7 @@ static int value_count(grib_accessor* a,long* count)
return ret;
}
static int unpack_double(grib_accessor* a, double* val, size_t *len)
static int unpack_double_standard(grib_accessor* a, double* val, size_t *len)
{
grib_accessor_data_complex_packing* self = (grib_accessor_data_complex_packing*)a;
grib_handle* gh = grib_handle_of_accessor(a);
@ -446,6 +445,224 @@ static int unpack_double(grib_accessor* a, double* val, size_t *len)
return ret;
}
static int unpack_double_optimised(grib_accessor* a, double* val, size_t *len)
{
grib_accessor_data_complex_packing* self = (grib_accessor_data_complex_packing*)a;
grib_handle* gh = grib_handle_of_accessor(a);
size_t i = 0;
int ret = GRIB_SUCCESS;
long hcount = 0;
long lcount = 0;
long hpos = 0;
long lup = 0;
long mmax = 0;
long n_vals = 0;
double *scals = NULL;
double *pscals=NULL,*pval=NULL;
double s = 0;
double d = 0;
double laplacianOperator = 0;
unsigned char* buf = NULL;
unsigned char* hres = NULL;
unsigned char* lres = NULL;
unsigned long packed_offset;
long lpos = 0;
long maxv = 0;
long GRIBEX_sh_bug_present =0;
long ieee_floats = 0;
long offsetdata = 0;
long bits_per_value = 0;
double reference_value = 0;
long binary_scale_factor = 0;
long decimal_scale_factor = 0;
long sub_j= 0;
long sub_k= 0;
long sub_m= 0;
long pen_j= 0;
long pen_k= 0;
long pen_m= 0;
double operat= 0;
int bytes;
int err=0;
decode_float_proc decode_float = NULL;
err=grib_value_count(a,&n_vals);
if (err) return err;
if(*len < n_vals){
*len = n_vals;
return GRIB_ARRAY_TOO_SMALL;
}
if((ret = grib_get_long_internal(gh,self->offsetdata,&offsetdata))
!= GRIB_SUCCESS) return ret;
if((ret = grib_get_long_internal(gh,self->bits_per_value,&bits_per_value))
!= GRIB_SUCCESS) return ret;
if((ret = grib_get_double_internal(gh,self->reference_value,&reference_value))
!= GRIB_SUCCESS) return ret;
if((ret = grib_get_long_internal(gh,self->binary_scale_factor,&binary_scale_factor))
!= GRIB_SUCCESS) return ret;
if((ret = grib_get_long_internal(gh,self->decimal_scale_factor,&decimal_scale_factor))
!= GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->GRIBEX_sh_bug_present,&GRIBEX_sh_bug_present))
!= GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->ieee_floats,&ieee_floats)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_double_internal(gh,self->laplacianOperator,&laplacianOperator))
!= GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->sub_j,&sub_j)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->sub_k,&sub_k)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->sub_m,&sub_m)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->pen_j,&pen_j)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->pen_k,&pen_k)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->pen_m,&pen_m)) != GRIB_SUCCESS)
return ret;
self->dirty=0;
switch (ieee_floats) {
case 0:
decode_float=grib_long_to_ibm;
bytes=4;
break;
case 1:
decode_float=grib_long_to_ieee;
bytes=4;
break;
case 2:
decode_float=grib_long_to_ieee64;
bytes=8;
break;
default:
return GRIB_NOT_IMPLEMENTED;
}
Assert (sub_j == sub_k);
Assert (sub_j == sub_m);
Assert (pen_j == pen_k);
Assert (pen_j == pen_m);
buf = (unsigned char*)gh->buffer->data;
maxv = pen_j+1;
buf += grib_byte_offset(a);
hres = buf;
lres = buf;
if (pen_j == sub_j) {
n_vals = (pen_j+1)*(pen_j+2);
d = grib_power(-decimal_scale_factor,10) ;
grib_ieee_decode_array(a->context,buf,n_vals,bytes,val);
if (d) {
for (i=0;i<n_vals;i++) val[i]*=d;
}
return 0;
}
packed_offset = grib_byte_offset(a) + 4*(sub_k+1)*(sub_k+2);
lpos = 8*(packed_offset-offsetdata);
s = grib_power(binary_scale_factor,2);
d = grib_power(-decimal_scale_factor,10) ;
scals = (double*)grib_context_malloc(a->context,maxv*sizeof(double));
Assert(scals);
scals[0] = 0;
for(i=1;i<maxv;i++){
operat = pow(i*(i+1),laplacianOperator);
if(operat != 0)
scals[i] = (1.0/operat);
else{
grib_context_log(a->context,GRIB_LOG_WARNING,
"COMPLEX_PACKING : problem with operator div by zero at index %d of %d \n",
i , maxv);
scals[i] = 0;
}
}
/*
printf("UNPACKING LAPLACE=%.20f\n",laplacianOperator);
printf("packed offset=%ld\n",packed_offset);
for(i=0;i<maxv;i++)
printf("scals[%d]=%g\n",i,scals[i]);*/
i=0;
while(maxv>0)
{
lup=mmax;
if(sub_k>=0)
{
for(hcount=0;hcount<sub_k+1;hcount++)
{
val[i++] = decode_float(grib_decode_unsigned_long(hres,&hpos,32));
val[i++] = decode_float(grib_decode_unsigned_long(hres,&hpos,32));
if (GRIBEX_sh_bug_present && hcount==sub_k){
/* bug in ecmwf data, last row (K+1)is scaled but should not */
val[i-2] *= scals[lup];
val[i-1] *= scals[lup];
}
lup++;
}
sub_k--;
}
pscals=scals+lup;
pval=val+i;
#if FAST_BIG_ENDIAN
grib_decode_double_array_complex(lres,
&lpos,bits_per_value,
reference_value,s,pscals,(maxv-hcount)*2,pval);
i+=(maxv-hcount)*2;
#else
(void)pscals; /* suppress gcc warning */
(void)pval; /* suppress gcc warning */
for(lcount=hcount; lcount < maxv ; lcount++)
{
val[i++] = d * (double) ((grib_decode_unsigned_long(lres, &lpos,
bits_per_value)*s)+reference_value)*scals[lup];
val[i++] = d * (double) ((grib_decode_unsigned_long(lres, &lpos,
bits_per_value)*s)+reference_value)*scals[lup];
lup++;
}
#endif
maxv--;
hcount=0;
mmax++;
}
Assert(*len >= i);
*len = i;
grib_context_free(a->context,scals);
return ret;
}
#define MAXVAL(a,b) a>b?a:b
@ -552,9 +769,8 @@ static double calculate_pfactor(grib_context *ctx,const double* spectralField, l
return pFactor;
}
static int pack_double(grib_accessor* a, const double* val, size_t *len) {
static int pack_double_standard(grib_accessor* a, const double* val, size_t *len)
{
grib_accessor_data_complex_packing* self = (grib_accessor_data_complex_packing*)a;
grib_handle* gh = grib_handle_of_accessor(a);
@ -647,7 +863,6 @@ static int pack_double(grib_accessor* a, const double* val, size_t *len) {
self->dirty=1;
switch (ieee_floats) {
case 0:
encode_float =grib_ibm_to_long;
@ -725,7 +940,6 @@ static int pack_double(grib_accessor* a, const double* val, size_t *len) {
for(i=1;i<maxv;i++)
scals[i] = ((double)pow(i*(i+1),laplacianOperator));
i=0;
mmax = 0;
@ -899,5 +1113,376 @@ static int pack_double(grib_accessor* a, const double* val, size_t *len) {
grib_context_free(a->context,scals);
return ret;
}
static int pack_double_optimised(grib_accessor* a, const double* val, size_t *len)
{
grib_accessor_data_complex_packing* self = (grib_accessor_data_complex_packing*)a;
grib_handle* gh = grib_handle_of_accessor(a);
size_t i = 0;
int ret = GRIB_SUCCESS;
long hcount = 0;
long lcount = 0;
long hpos = 0;
long lup = 0;
long mmax = 0;
long n_vals = 0;
double *scals = NULL;
double s = 0;
double d = 0;
unsigned char* buf = NULL;
size_t buflen = 0;
size_t hsize = 0;
size_t lsize = 0;
unsigned char* hres = NULL;
unsigned char* lres = NULL;
long lpos = 0;
long maxv = 0;
long offsetdata = 0;
long bits_per_value = 0;
double reference_value = 0;
long binary_scale_factor = 0;
long decimal_scale_factor = 0;
long optimize_scaling_factor = 0;
long laplacianOperatorIsSet = 0;
double laplacianOperator = 0;
long sub_j= 0;
long sub_k= 0;
long sub_m= 0;
long pen_j= 0;
long pen_k= 0;
long pen_m= 0;
long GRIBEX_sh_bug_present =0;
long ieee_floats =0;
double min = 0;
double max = 0;
double current_val = 0;
short mixmax_unset = 0;
int bytes;
encode_float_proc encode_float = NULL;
if (*len ==0) return GRIB_NO_VALUES;
if((ret = grib_get_long_internal(gh,self->offsetdata,&offsetdata)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->bits_per_value,&bits_per_value)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->decimal_scale_factor,&decimal_scale_factor)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->optimize_scaling_factor,&optimize_scaling_factor)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->GRIBEX_sh_bug_present,&GRIBEX_sh_bug_present)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->ieee_floats,&ieee_floats)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->laplacianOperatorIsSet,&laplacianOperatorIsSet)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_double_internal(gh,self->laplacianOperator,&laplacianOperator)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->sub_j,&sub_j)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->sub_k,&sub_k)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->sub_m,&sub_m)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->pen_j,&pen_j)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->pen_k,&pen_k)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(gh,self->pen_m,&pen_m)) != GRIB_SUCCESS)
return ret;
self->dirty=1;
switch (ieee_floats) {
case 0:
encode_float =grib_ibm_to_long;
bytes=4;
break;
case 1:
encode_float =grib_ieee_to_long;
bytes=4;
break;
case 2:
encode_float =grib_ieee64_to_long;
bytes=8;
break;
default:
return GRIB_NOT_IMPLEMENTED;
}
Assert (sub_j == sub_k); Assert( sub_j == sub_m);
Assert (pen_j == pen_k); Assert( pen_j == pen_m);
n_vals = (pen_j+1)*(pen_j+2);
if(*len != n_vals){
grib_context_log(a->context,GRIB_LOG_ERROR,"COMPLEX_PACKING : wrong number of values, expected %d - got %d",n_vals,*len);
return GRIB_INTERNAL_ERROR;
}
if (pen_j == sub_j) {
double* values;
d = grib_power(decimal_scale_factor,10) ;
if (d) {
values=(double*)grib_context_malloc_clear(a->context,sizeof(double)*n_vals);
for (i=0;i<n_vals;i++) values[i]=val[i]*d;
} else {
values=(double*)val;
}
buflen=n_vals*bytes;
buf = (unsigned char*)grib_context_malloc_clear(a->context,buflen);
grib_ieee_encode_array(a->context,values,n_vals,bytes,buf);
if (d) grib_context_free(a->context,values);
grib_buffer_replace(a, buf, buflen,1,1);
grib_context_free(a->context,buf);
return 0;
}
if(!laplacianOperatorIsSet) {
laplacianOperator = calculate_pfactor(a->context,val,pen_j,sub_j);
if((ret = grib_set_double_internal(gh,self->laplacianOperator,laplacianOperator))
!= GRIB_SUCCESS) return ret;
grib_get_double_internal(gh,self->laplacianOperator,&laplacianOperator);
}
hsize = 4*(sub_k+1)*(sub_k+2);
lsize = ((n_vals - ((sub_k+1)*(sub_k+2)))*bits_per_value)/8;
buflen = hsize+lsize;
buf = (unsigned char*)grib_context_malloc(a->context,buflen);
hres = buf;
lres = buf+hsize;
maxv = pen_j+1;
lpos = 0;
hpos = 0;
scals = (double*) grib_context_malloc(a->context,maxv*sizeof(double));
Assert(scals);
scals[0] =0;
for(i=1;i<maxv;i++)
scals[i] = ((double)pow(i*(i+1),laplacianOperator));
i=0;
mmax = 0;
maxv = pen_j+1;
i=0;
lcount=0;
hcount=0;
sub_k = sub_j;
while(maxv>0)
{
lup=mmax;
if(sub_k>=0)
{
i += 2*(sub_k+1);
lup += sub_k+1 ;
hcount += sub_k+1 ;
sub_k--;
}
for(lcount=hcount; lcount < maxv ; lcount++)
{
current_val = ((val[i++]) * scals[lup]);
if(mixmax_unset == 0){
max = current_val;
min = current_val;
mixmax_unset = 1;
}
if(current_val > max) max = current_val;
if(current_val < min) min = current_val;
current_val = ((val[i++]) * scals[lup]);
if(current_val > max) max = current_val;
if(current_val < min) min = current_val;
lup++;
}
maxv--;
hcount=0;
mmax++;
}
Assert(optimize_scaling_factor);
ret = grib_optimize_decimal_factor (a, self->reference_value,
max, min, bits_per_value, 0, 1,
&decimal_scale_factor,
&binary_scale_factor,
&reference_value);
if (ret !=GRIB_SUCCESS) {
grib_context_log(gh->context,GRIB_LOG_ERROR,
"unable to find nearest_smaller_value of %g for %s",min,self->reference_value);
return GRIB_INTERNAL_ERROR;
}
d = grib_power(+decimal_scale_factor,10);
s = grib_power(- binary_scale_factor, 2);
i=0;
mmax = 0;
maxv = pen_j+1;
i=0;
lcount=0;
hcount=0;
sub_k = sub_j;
while(maxv>0)
{
lup=mmax;
if(sub_k>=0)
{
for(hcount=0;hcount<sub_k+1;hcount++)
{
if ( GRIBEX_sh_bug_present && hcount==sub_k ) {
/* _test(val[i]*d*scals[lup],1); */
grib_encode_unsigned_long(hres, encode_float((val[i++]*d)*scals[lup]) , &hpos, 32);
/* _test(val[i]*d*scals[lup],1); */
grib_encode_unsigned_long(hres, encode_float((val[i++]*d)*scals[lup]) , &hpos, 32);
}else{
/* _test(val[i]*d,0); */
grib_encode_unsigned_long(hres, encode_float(val[i++]) , &hpos, 32);
/* _test(val[i]*d,0); */
grib_encode_unsigned_long(hres, encode_float(val[i++]) , &hpos, 32);
}
lup++;
}
sub_k--;
}
#if FAST_BIG_ENDIAN
grib_encode_double_array_complex((maxv-hcount)*2,&(val[i]),bits_per_value,reference_value,&(scals[lup]),d,s,lres,&lpos);
i+=(maxv-hcount)*2;
#else
if (bits_per_value % 8) {
for(lcount=hcount; lcount < maxv ; lcount++)
{
current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
if(current_val < 0)
grib_context_log(a->context,GRIB_LOG_ERROR,
"COMPLEX_PACKING : negative coput before packing (%g)", current_val);
grib_encode_unsigned_longb(lres, current_val, &lpos, bits_per_value);
current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
if(current_val < 0)
grib_context_log(a->context,GRIB_LOG_ERROR,
"COMPLEX_PACKING : negative coput before packing (%g)", current_val);
grib_encode_unsigned_longb(lres, current_val, &lpos, bits_per_value);
lup++;
}
} else {
for(lcount=hcount; lcount < maxv ; lcount++)
{
current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
if(current_val < 0)
grib_context_log(a->context,GRIB_LOG_ERROR,
"COMPLEX_PACKING : negative coput before packing (%g)", current_val);
grib_encode_unsigned_long(lres, current_val, &lpos, bits_per_value);
current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
if(current_val < 0)
grib_context_log(a->context,GRIB_LOG_ERROR,
"COMPLEX_PACKING : negative coput before packing (%g)", current_val);
grib_encode_unsigned_long(lres, current_val, &lpos, bits_per_value);
lup++;
}
}
#endif
maxv--;
hcount=0;
mmax++;
}
if(((hpos/8) != hsize) &&((lpos/8) != lsize))
{
grib_context_log(a->context,GRIB_LOG_ERROR,
"COMPLEX_PACKING : Mismatch in packing between high resolution and low resolution part");
grib_context_free(a->context,buf);
grib_context_free(a->context,scals);
return GRIB_INTERNAL_ERROR;
}
buflen = ((hpos + lpos)/8);
if((ret = grib_set_double_internal(gh,self->reference_value, reference_value)) != GRIB_SUCCESS)
return ret;
{
/* Make sure we can decode it again */
double ref = 1e-100;
grib_get_double_internal(gh,self->reference_value,&ref);
Assert(ref == reference_value);
}
if((ret = grib_set_long_internal(gh,self->binary_scale_factor, binary_scale_factor)) != GRIB_SUCCESS)
return ret;
if((ret = grib_set_long_internal(gh,self->decimal_scale_factor,decimal_scale_factor)) != GRIB_SUCCESS)
return ret;
grib_buffer_replace(a, buf, buflen,1,1);
grib_context_free(a->context,buf);
grib_context_free(a->context,scals);
return ret;
}
/* The driver unpack and pack routines. See ECC-261 */
static int unpack_double(grib_accessor* a, double* val, size_t *len)
{
grib_accessor_data_complex_packing* self = (grib_accessor_data_complex_packing*)a;
grib_handle* gh = grib_handle_of_accessor(a);
int ret = GRIB_SUCCESS;
long optimize_scaling_factor = 0;
if ((ret = grib_get_long_internal(gh, self->optimize_scaling_factor, &optimize_scaling_factor)) != GRIB_SUCCESS)
return ret;
if (optimize_scaling_factor) {
return unpack_double_optimised(a, val, len);
} else {
return unpack_double_standard(a, val, len);
}
}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
grib_accessor_data_complex_packing* self = (grib_accessor_data_complex_packing*)a;
grib_handle* gh = grib_handle_of_accessor(a);
int ret = GRIB_SUCCESS;
long optimize_scaling_factor = 0;
if ((ret = grib_get_long_internal(gh, self->optimize_scaling_factor, &optimize_scaling_factor)) != GRIB_SUCCESS)
return ret;
if (optimize_scaling_factor) {
return pack_double_optimised(a, val, len);
} else {
return pack_double_standard(a, val, len);
}
}

View File

@ -204,13 +204,23 @@ static void init_class(grib_accessor_class* c)
#define MAX_NUMBER_OF_GROUPS 65534
#define EFDEBUG 0
static unsigned long nbits[32]={
0x1, 0x2, 0x4, 0x8, 0x10, 0x20,
0x40, 0x80, 0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000,
0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000,
0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000,
0x40000000, 0x80000000
static unsigned long nbits[64]={
0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80,
0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000,
0x10000, 0x20000, 0x40000, 0x80000,
0x100000, 0x200000, 0x400000, 0x800000,
0x1000000, 0x2000000, 0x4000000, 0x8000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x100000000, 0x200000000, 0x400000000, 0x800000000,
0x1000000000, 0x2000000000, 0x4000000000, 0x8000000000,
0x10000000000, 0x20000000000, 0x40000000000, 0x80000000000,
0x100000000000, 0x200000000000, 0x400000000000, 0x800000000000,
0x1000000000000, 0x2000000000000, 0x4000000000000, 0x8000000000000,
0x10000000000000, 0x20000000000000, 0x40000000000000, 0x80000000000000,
0x100000000000000, 0x200000000000000, 0x400000000000000, 0x800000000000000,
0x1000000000000000, 0x2000000000000000, 0x4000000000000000, 0x8000000000000000
};
static long number_of_bits(grib_handle*h, unsigned long x)
@ -600,7 +610,7 @@ static void grib_split_long_groups(grib_handle* hand, grib_context* c,long* numb
grib_context_free(c,localFirstOrderValues);
}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
static int pack_double_standard(grib_accessor* a, const double* val, size_t *len)
{
grib_accessor_data_g1second_order_general_extended_packing* self = (grib_accessor_data_g1second_order_general_extended_packing*)a;
int ret=0;
@ -643,9 +653,6 @@ static int pack_double(grib_accessor* a, const double* val, size_t *len)
long dataHeadersLength,widthsLength,lengthsLength,firstOrderValuesLength;
long decimal_scale_factor;
grib_handle* handle = grib_handle_of_accessor(a);
long optimize_scaling_factor = 0;
grib_context* c=handle->context;
int compat_gribex = c->gribex_mode_on && self->edition==1;
self->dirty=1;
@ -1207,6 +1214,628 @@ static int pack_double(grib_accessor* a, const double* val, size_t *len)
return ret;
}
static int pack_double_optimised(grib_accessor* a, const double* val, size_t *len)
{
grib_accessor_data_g1second_order_general_extended_packing* self = (grib_accessor_data_g1second_order_general_extended_packing*)a;
int ret=0;
int grib2=0;
long bits_per_value,orderOfSPD,binary_scale_factor;
long numberOfValues;
double max,min;
double decimal,divisor;
double reference_value;
size_t size,sizebits;
long half_byte;
long* X;
long* Xp;
long i;
long incrementGroupLengthA,groupWidthA,prevGroupLength,offsetD,remainingValuesB,groupLengthB;
long maxB,minB,maxAB,minAB;
long offsetBeforeData,offsetSection4;
unsigned char* buffer = NULL;
long maxWidth,maxLength,widthOfWidths,NL,widthOfLengths,N1,N2,extraValues,codedNumberOfGroups,numberOfSecondOrderPackedValues;
long pos;
long numberOfGroups;
long groupLengthC,groupLengthA,remainingValues,count;
long maxA=0,minA=0;
long maxC,minC,offsetC;
long maxAC,minAC;
long range,bias=0,maxSPD;
long firstOrderValuesMax,offset,groupLength,j,groupWidth,firstOrderValue,lengthOfSecondOrderValues;
long *groupLengths,*groupWidths,*firstOrderValues;
/* long groupLengths[MAX_NUMBER_OF_GROUPS],groupWidths[MAX_NUMBER_OF_GROUPS],firstOrderValues[MAX_NUMBER_OF_GROUPS]; */
/* TODO put these parameters in def file */
long startGroupLength=15;
long incrementGroupLength=3;
long minGroupLength=3;
long widthOfSPD=0,widthOfBias=0;
long *offsets;
long widthOfFirstOrderValues;
int computeGroupA=1;
long dataHeadersLength,widthsLength,lengthsLength,firstOrderValuesLength;
long decimal_scale_factor;
grib_handle* handle = grib_handle_of_accessor(a);
long optimize_scaling_factor = 0;
grib_context* c=handle->context;
int compat_gribex = c->gribex_mode_on && self->edition==1;
self->dirty=1;
numberOfValues=*len;
min = max = val[0];
for(i=1;i< numberOfValues;i++) {
if (val[i] > max ) max = val[i];
if (val[i] < min ) min = val[i];
}
if((ret=grib_get_long_internal(handle,self->bits_per_value,&bits_per_value)) != GRIB_SUCCESS)
return ret;
if((ret = grib_get_long_internal(handle,self->optimize_scaling_factor, &optimize_scaling_factor))
!= GRIB_SUCCESS)
return ret;
Assert(optimize_scaling_factor);
if ((ret=grib_optimize_decimal_factor (a, self->reference_value,
max, min, bits_per_value,
compat_gribex, 1,
&decimal_scale_factor, &binary_scale_factor, &reference_value)) != GRIB_SUCCESS)
return ret;
decimal = grib_power(decimal_scale_factor,10);
divisor = grib_power(-binary_scale_factor,2);
min = min * decimal;
max = max * decimal;
if((ret = grib_set_long_internal(handle,self->decimal_scale_factor, decimal_scale_factor)) !=
GRIB_SUCCESS)
return ret;
if((ret = grib_set_long_internal(handle,self->binary_scale_factor, binary_scale_factor)) !=
GRIB_SUCCESS)
return ret;
if((ret = grib_set_double_internal(handle,self->reference_value, reference_value)) !=
GRIB_SUCCESS)
return ret;
if((ret=grib_get_long_internal(handle,self->offsetdata,&offsetBeforeData)) != GRIB_SUCCESS)
return ret;
if((ret=grib_get_long_internal(handle,self->offsetsection,&offsetSection4)) != GRIB_SUCCESS)
return ret;
if((ret=grib_get_long_internal(handle,self->orderOfSPD,&orderOfSPD)) != GRIB_SUCCESS)
return ret;
X=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfValues);
for(i=0;i< numberOfValues;i++){
X[i] = (((val[i]*decimal)-reference_value)*divisor)+0.5;
}
groupLengths=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfValues);
groupWidths=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfValues);
firstOrderValues=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfValues);
/* spatial differencing */
switch (orderOfSPD) {
case 1:
for (i=numberOfValues-1;i>0;i--) {
X[i]-=X[i-1];
}
break;
case 2:
for (i=numberOfValues-1;i>1;i--) {
X[i]-=2*X[i-1]-X[i-2];
}
break;
case 3:
for (i=numberOfValues-1;i>2;i--) {
X[i]-=3*(X[i-1]-X[i-2])+X[i-3];
}
break;
}
if (orderOfSPD) {
Assert(orderOfSPD >=0 && orderOfSPD < numberOfValues);
bias=X[orderOfSPD];
for (i=orderOfSPD+1;i<numberOfValues;i++) {
if ( bias > X[i] ) bias=X[i];
}
for (i=orderOfSPD;i<numberOfValues;i++) {
X[i]-=bias;
}
maxSPD=X[0];
for (i=1;i<orderOfSPD;i++) {
if ( maxSPD < X[i] ) maxSPD=X[i];
}
/* widthOfSPD=(long)ceil(log((double)(maxSPD+1))/log(2.0)); */
widthOfSPD=number_of_bits(handle, maxSPD);
widthOfBias=number_of_bits(handle, labs(bias))+1;
if ( widthOfSPD < widthOfBias ) widthOfSPD=widthOfBias;
}
/* end of spatial differencing */
count=orderOfSPD;
remainingValues=numberOfValues-count;
numberOfGroups=0;
incrementGroupLengthA=startGroupLength;
computeGroupA=1;
while (remainingValues) {
/* group A created with length=incrementGroupLengthA (if enough values remain)
incrementGroupLengthA=startGroupLength always except when coming from an A+C or A+B ok branch
*/
groupLengthA= incrementGroupLengthA < remainingValues ? incrementGroupLengthA : remainingValues ;
if (computeGroupA) {
maxA=X[count];
minA=X[count];
for (i=1;i<groupLengthA;i++) {
DebugAssertAccess(X, count+i, numberOfValues);
if (maxA<X[count+i]) maxA=X[count+i];
if (minA>X[count+i]) minA=X[count+i];
}
}
groupWidthA=number_of_bits(handle, maxA-minA);
range=(long)grib_power(groupWidthA,2)-1;
offsetC=count+groupLengthA;
if (offsetC==numberOfValues) {
/* no more values close group A and end loop */
groupLengths[numberOfGroups]=groupLengthA;
groupWidths[numberOfGroups]=groupWidthA;
/* firstOrderValues[numberOfGroups]=minA; */
/* to optimise the width of first order variable */
firstOrderValues[numberOfGroups] = maxA-range > 0 ? maxA-range : 0;
numberOfGroups++;
break;
}
/* group C created with length=incrementGroupLength (fixed)
or remaining values if close to end
*/
groupLengthC=incrementGroupLength;
if ( groupLengthC + offsetC > numberOfValues - startGroupLength/2) {
groupLengthC=numberOfValues-offsetC;
}
maxC=X[offsetC];
minC=X[offsetC];
for (i=1;i<groupLengthC;i++) {
DebugAssertAccess(X, offsetC+i, numberOfValues);
if (maxC<X[offsetC+i]) maxC=X[offsetC+i];
if (minC>X[offsetC+i]) minC=X[offsetC+i];
}
maxAC= maxA > maxC ? maxA : maxC;
minAC= minA < minC ? minA : minC;
/* check if A+C can be represented with the same width as A*/
if (maxAC-minAC > range) {
/* A could not be expanded adding C. Check if A could be expanded taking
some elements from preceding group. The condition is always that width of
A doesn't increase.
*/
if (numberOfGroups>0 && groupWidths[numberOfGroups-1] > groupWidthA ) {
prevGroupLength=groupLengths[numberOfGroups-1]-incrementGroupLength;
offsetC=count-incrementGroupLength;
/* preceding group length cannot be less than a minimum value */
while (prevGroupLength >= minGroupLength) {
maxAC=maxA;
minAC=minA;
for (i=0;i<incrementGroupLength;i++) {
if (maxAC<X[offsetC+i]) maxAC=X[offsetC+i];
if (minAC>X[offsetC+i]) minAC=X[offsetC+i];
}
/* no more elements can be transfered, exit loop*/
if (maxAC-minAC > range) break;
maxA=maxAC;
minA=minAC;
groupLengths[numberOfGroups-1]-=incrementGroupLength;
groupLengthA+=incrementGroupLength;
count-=incrementGroupLength;
remainingValues+=incrementGroupLength;
offsetC-=incrementGroupLength;
prevGroupLength-=incrementGroupLength;
}
}
/* close group A*/
groupLengths[numberOfGroups]=groupLengthA;
groupWidths[numberOfGroups]=groupWidthA;
/* firstOrderValues[numberOfGroups]=minA; */
/* to optimise the width of first order variable */
firstOrderValues[numberOfGroups] = maxA-range > 0 ? maxA-range : 0;
count+=groupLengthA;
remainingValues-=groupLengthA;
numberOfGroups++;
/* incrementGroupLengthA is reset to the fixed startGroupLength as it
could have been changed after the A+C or A+B ok condition.
*/
incrementGroupLengthA=startGroupLength;
computeGroupA=1;
#if 0
if (numberOfGroups==MAX_NUMBER_OF_GROUPS) {
groupLengthA= remainingValues ;
maxA=X[count];
minA=X[count];
for (i=1;i<groupLengthA;i++) {
if (maxA<X[count+i]) maxA=X[count+i];
if (minA>X[count+i]) minA=X[count+i];
}
groupWidthA=number_of_bits(maxA-minA);
range=(long)grib_power(groupWidthA,2)-1;
groupLengths[numberOfGroups]=groupLengthA;
groupWidths[numberOfGroups]=groupWidthA;
firstOrderValues[numberOfGroups] = maxA-range > 0 ? maxA-range : 0;
break;
}
#endif
continue;
}
/* A+C could be coded with the same width as A*/
offsetD=offsetC+groupLengthC;
if (offsetD==numberOfValues) {
groupLengths[numberOfGroups]=groupLengthA+groupLengthC;
groupWidths[numberOfGroups]=groupWidthA;
/* range of AC is the same as A*/
/* firstOrderValues[numberOfGroups]=minAC; */
/* to optimise the width of first order variable */
firstOrderValues[numberOfGroups] = maxAC-range > 0 ? maxAC-range : 0;
numberOfGroups++;
break;
}
/* group B is created with length startGroupLength, starting at the
same offset as C.
*/
remainingValuesB=numberOfValues-offsetC;
groupLengthB= startGroupLength < remainingValuesB ? startGroupLength : remainingValuesB ;
maxB=maxC;
minB=minC;
for (i=groupLengthC;i<groupLengthB;i++) {
if (maxB<X[offsetC+i]) maxB=X[offsetC+i];
if (minB>X[offsetC+i]) minB=X[offsetC+i];
}
/* check if group B can be coded with a smaller width than A */
if (maxB-minB <= range/2 && range>0 ) {
/* TODO Add code to try if A can be expanded taking some elements
from the left (preceding) group.
A possible variation is to do this left check (and the previous one)
in the final loop when checking that the width of each group.
*/
/* close group A and continue loop*/
groupLengths[numberOfGroups]=groupLengthA;
groupWidths[numberOfGroups]=groupWidthA;
/* firstOrderValues[numberOfGroups]=minA; */
/* to optimise the width of first order variable */
firstOrderValues[numberOfGroups] = maxA-range > 0 ? maxA-range : 0;
count+=groupLengthA;
remainingValues-=groupLengthA;
numberOfGroups++;
#if 0
if (numberOfGroups==MAX_NUMBER_OF_GROUPS) {
groupLengthA= remainingValues ;
maxA=X[count];
minA=X[count];
for (i=1;i<groupLengthA;i++) {
if (maxA<X[count+i]) maxA=X[count+i];
if (minA>X[count+i]) minA=X[count+i];
}
groupWidthA=number_of_bits(maxA-minA);
range=(long)grib_power(groupWidthA,2)-1;
groupLengths[numberOfGroups]=groupLengthA;
groupWidths[numberOfGroups]=groupWidthA;
firstOrderValues[numberOfGroups] = maxA-range > 0 ? maxA-range : 0;
break;
}
#endif
incrementGroupLengthA=startGroupLength;
computeGroupA=1;
continue;
}
/* check if A+B can be coded with same with as A */
maxAB= maxA > maxB ? maxA : maxB;
minAB= minA < minB ? minA : minB;
if (maxAB-minAB <= range) {
/* A+B can be merged. The increment used at the beginning of the loop to
build group C is increased to the size of group B
*/
incrementGroupLengthA+=groupLengthB;
maxA=maxAB;
minA=minAB;
computeGroupA=0;
continue;
}
/* A+B cannot be merged, A+C can be merged*/
incrementGroupLengthA+=groupLengthC;
computeGroupA=1;
} /* end of the while*/
/* computing bitsPerValue as the number of bits needed to represent
the firstOrderValues.
*/
max=firstOrderValues[0];
min=firstOrderValues[0];
for (i=1;i<numberOfGroups;i++) {
if (max<firstOrderValues[i]) max=firstOrderValues[i];
if (min>firstOrderValues[i]) min=firstOrderValues[i];
}
widthOfFirstOrderValues=number_of_bits(handle, max-min);
firstOrderValuesMax=(long)grib_power(widthOfFirstOrderValues,2)-1;
if (numberOfGroups>2) {
/* loop through all the groups except the last in reverse order to
check if each group width is still appropriate for the group.
Focus on groups which have been shrank as left groups of an A group taking
some of their elements.
*/
offsets=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfGroups);
offsets[0]=orderOfSPD;
for (i=1;i<numberOfGroups;i++) offsets[i]=offsets[i-1]+groupLengths[i-1];
for (i=numberOfGroups-2;i>=0;i--) {
offset=offsets[i];
groupLength=groupLengths[i];
if (groupLength >= startGroupLength) continue;
max=X[offset];
min=X[offset];
for (j=1;j<groupLength;j++) {
if (max<X[offset+j]) max=X[offset+j];
if (min>X[offset+j]) min=X[offset+j];
}
groupWidth=number_of_bits(handle, max-min);
range=(long)grib_power(groupWidth,2)-1;
/* width of first order values has to be unchanged.*/
for (j=groupWidth;j<groupWidths[i];j++) {
firstOrderValue= max>range ? max-range : 0;
if (firstOrderValue <= firstOrderValuesMax ) {
groupWidths[i]=j;
firstOrderValues[i]=firstOrderValue;
break;
}
}
offsetC=offset;
/* group width of the current group (i) can have been reduced
and it is worth to try to expand the group to get some elements
from the left group if it has bigger width.
*/
if (i>0 && (groupWidths[i-1] > groupWidths[i]) ) {
prevGroupLength=groupLengths[i-1]-incrementGroupLength;
offsetC-=incrementGroupLength;
while (prevGroupLength >= minGroupLength) {
for (j=0;j<incrementGroupLength;j++) {
if (max<X[offsetC+j]) max=X[offsetC+j];
if (min>X[offsetC+j]) min=X[offsetC+j];
}
/* width of first order values has to be unchanged*/
firstOrderValue=max>range ? max-range : 0;
if (max-min > range || firstOrderValue > firstOrderValuesMax ) break;
groupLengths[i-1]-=incrementGroupLength;
groupLengths[i]+=incrementGroupLength;
firstOrderValues[i]=firstOrderValue;
offsetC-=incrementGroupLength;
prevGroupLength-=incrementGroupLength;
}
}
}
grib_context_free(a->context,offsets);
}
maxWidth=groupWidths[0];
maxLength=groupLengths[0];
for (i=1;i<numberOfGroups;i++) {
if (maxWidth<groupWidths[i]) maxWidth=groupWidths[i];
if (maxLength<groupLengths[i]) maxLength=groupLengths[i];
}
if (maxWidth < 0 || maxLength < 0) {
grib_context_log(a->parent->h->context, GRIB_LOG_ERROR, "Cannot compute parameters for second order packing.");
return GRIB_ENCODING_ERROR;
}
widthOfWidths=number_of_bits(handle, maxWidth);
widthOfLengths=number_of_bits(handle, maxLength);
lengthOfSecondOrderValues=0;
for ( i=0; i<numberOfGroups;i++) {
lengthOfSecondOrderValues+=groupLengths[i]*groupWidths[i];
}
if (!a->context->no_big_group_split) {
grib_split_long_groups(handle, a->context,&numberOfGroups,&lengthOfSecondOrderValues,
groupLengths,&widthOfLengths,groupWidths,widthOfWidths,
firstOrderValues,widthOfFirstOrderValues);
}
Xp=X+orderOfSPD;
for ( i=0; i<numberOfGroups;i++) {
for (j=0; j<groupLengths[i]; j++) {
*(Xp++)-=firstOrderValues[i];
}
}
/* start writing to message */
/* writing SPD */
if (orderOfSPD) {
if((ret = grib_set_long_internal(handle,self->widthOfSPD, widthOfSPD))
!= GRIB_SUCCESS)
return ret;
}
/* end writing SPD */
if((ret = grib_set_long_internal(handle,self->widthOfFirstOrderValues, widthOfFirstOrderValues))
!= GRIB_SUCCESS)
return ret;
dataHeadersLength=25;
if (orderOfSPD) dataHeadersLength+=1+((orderOfSPD+1)*widthOfSPD+7)/8;
widthsLength=(widthOfWidths*numberOfGroups+7)/8;
lengthsLength=(widthOfLengths*numberOfGroups+7)/8;
firstOrderValuesLength=(widthOfFirstOrderValues*numberOfGroups+7)/8;
NL=widthsLength+dataHeadersLength+1;
N1=NL+lengthsLength;
N2=N1+firstOrderValuesLength;
NL= NL > 65535 ? 65535 : NL;
N2= N2 > 65535 ? 65535 : N2;
N1= N1 > 65535 ? 65535 : N1;
grib_set_long(handle,self->NL, NL);
grib_set_long(handle,self->N1, N1);
grib_set_long(handle,self->N2, N2);
if (numberOfGroups > 65535 ) {
extraValues=numberOfGroups/65536;
codedNumberOfGroups=numberOfGroups%65536;
} else {
extraValues=0;
codedNumberOfGroups=numberOfGroups;
}
/* if no extraValues key present it is a GRIB2*/
grib2=0;
if((ret = grib_set_long(handle,self->extraValues, extraValues)) != GRIB_SUCCESS) {
codedNumberOfGroups=numberOfGroups;
grib2=1;
}
if((ret = grib_set_long_internal(handle,self->codedNumberOfGroups, codedNumberOfGroups)) != GRIB_SUCCESS)
return ret;
numberOfSecondOrderPackedValues=numberOfValues-orderOfSPD;
if (!grib2 && numberOfSecondOrderPackedValues > 65535 )
numberOfSecondOrderPackedValues= 65535;
if((ret = grib_set_long_internal(handle,self->numberOfSecondOrderPackedValues, numberOfSecondOrderPackedValues))
!= GRIB_SUCCESS)
return ret;
if (grib2) {
if((ret = grib_set_long_internal(handle,self->bits_per_value, bits_per_value)) != GRIB_SUCCESS)
return ret;
} else {
if((ret = grib_set_long_internal(handle,self->bits_per_value, 0)) != GRIB_SUCCESS)
return ret;
}
if((ret = grib_set_long_internal(handle,self->widthOfWidths, widthOfWidths)) != GRIB_SUCCESS)
return ret;
if((ret = grib_set_long_internal(handle,self->widthOfLengths, widthOfLengths)) != GRIB_SUCCESS)
return ret;
lengthOfSecondOrderValues=0;
for ( i=0; i<numberOfGroups;i++) {
lengthOfSecondOrderValues+=groupLengths[i]*groupWidths[i];
}
size=(lengthOfSecondOrderValues+7)/8;
sizebits=lengthOfSecondOrderValues;
/* padding section 4 to an even number of octets*/
size = (size+offsetBeforeData-offsetSection4) % 2 ? size+1 : size;
half_byte=8*size-sizebits;
if((ret = grib_set_long_internal(handle,self->half_byte, half_byte)) != GRIB_SUCCESS)
return ret;
buffer=(unsigned char*)grib_context_malloc_clear(a->context,size);
pos=0;
if (orderOfSPD) {
long SPD[4]={0,};
size_t nSPD=orderOfSPD+1;
Assert(orderOfSPD<=3);
for (i=0;i<orderOfSPD;i++) SPD[i]=X[i];
SPD[orderOfSPD]=bias;
ret=grib_set_long_array_internal(handle,self->SPD,SPD,nSPD);
if(ret) return ret;
}
ret=grib_set_long_array_internal(handle,self->groupWidths,groupWidths,(size_t)numberOfGroups);
if(ret) return ret;
ret=grib_set_long_array_internal(handle,self->groupLengths,groupLengths,(size_t)numberOfGroups);
if(ret) return ret;
ret=grib_set_long_array_internal(handle,self->firstOrderValues,firstOrderValues,(size_t)numberOfGroups);
if(ret) return ret;
Xp=X+orderOfSPD;
pos=0;
count=0;
for (i=0;i<numberOfGroups;i++) {
if (groupWidths[i]>0) {
for (j=0;j<groupLengths[i];j++) {
#if EFDEBUG
printf("CXXXXX %ld %ld %ld %ld\n",count,*Xp,groupWidths[i],groupLengths[i]);
count++;
#endif
grib_encode_unsigned_longb(buffer,*(Xp++),&pos,groupWidths[i]);
}
} else {
Xp+=groupLengths[i];
#if EFDEBUG
count+=groupLengths[i];
#endif
}
}
/* ECC-259: Set correct number of values */
ret=grib_set_long_internal(a->parent->h,self->number_of_values, *len);
if(ret) return ret;
grib_buffer_replace(a, buffer, size,1,1);
grib_context_free(a->context,buffer);
grib_context_free(a->context,X);
grib_context_free(a->context,groupLengths);
grib_context_free(a->context,groupWidths);
grib_context_free(a->context,firstOrderValues);
return ret;
}
/* The driver pack routine. See ECC-261 */
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
grib_accessor_data_g1second_order_general_extended_packing* self = (grib_accessor_data_g1second_order_general_extended_packing*)a;
int ret = GRIB_SUCCESS;
grib_handle* handle = grib_handle_of_accessor(a);
long optimize_scaling_factor = 0;
if((ret = grib_get_long_internal(handle,self->optimize_scaling_factor, &optimize_scaling_factor)) != GRIB_SUCCESS)
return ret;
if (optimize_scaling_factor) {
return pack_double_optimised(a,val,len);
} else {
return pack_double_standard(a,val,len);
}
}
static void destroy(grib_context* context,grib_accessor* a)
{
grib_accessor_data_g1second_order_general_extended_packing *self =(grib_accessor_data_g1second_order_general_extended_packing*)a;