eccodes/src/grib_box_class_reduced_gaus...

240 lines
6.4 KiB
C

/*
* Copyright 2005-2015 ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/
#include "grib_api_internal.h"
/*
This is used by make_class.pl
START_CLASS_DEF
CLASS = box
SUPER = grib_box_class_gen
IMPLEMENTS = destroy
IMPLEMENTS = get_points
IMPLEMENTS = init
MEMBERS = double* lats
MEMBERS = size_t nlats
MEMBERS = double** lons
MEMBERS = long* nlons
MEMBERS = size_t size
END_CLASS_DEF
*/
/* START_CLASS_IMP */
/*
Don't edit anything between START_CLASS_IMP and END_CLASS_IMP
Instead edit values between START_CLASS_DEF and END_CLASS_DEF
or edit "box.class" and rerun ./make_class.pl
*/
static void init_class (grib_box_class*);
static int init (grib_box* box,grib_handle* h,grib_arguments* args);
static grib_points* get_points(grib_box* box, double north, double west, double south,double east,int *err);
static int destroy (grib_box* box);
typedef struct grib_box_reduced_gaussian{
grib_box box;
/* Members defined in gen */
/* Members defined in reduced_gaussian */
double* lats;
size_t nlats;
double** lons;
long* nlons;
size_t size;
} grib_box_reduced_gaussian;
extern grib_box_class* grib_box_class_gen;
static grib_box_class _grib_box_class_reduced_gaussian = {
&grib_box_class_gen, /* super */
"reduced_gaussian", /* name */
sizeof(grib_box_reduced_gaussian), /* size of instance */
0, /* inited */
&init_class, /* init_class */
&init, /* constructor */
&destroy, /* destructor */
&get_points, /* get points */
};
grib_box_class* grib_box_class_reduced_gaussian = &_grib_box_class_reduced_gaussian;
static void init_class(grib_box_class* c)
{
}
/* END_CLASS_IMP */
static int init(grib_box* box,grib_handle* h,grib_arguments* args)
{
grib_box_reduced_gaussian* self=(grib_box_reduced_gaussian*)box;
int n=1;
int ret=0;
char* key;
long* pl;
double lat_first,lat_last,lon_first,lon_last;
long order;
double *lats;
long j,l,ilon_first,ilon_last,i;
long row_count;
grib_context* c=box->context;
key = (char*)grib_arguments_get_name(h,args,n++);
ret=grib_get_double(h,key,&lat_first);
if (ret) return ret;
key = (char*)grib_arguments_get_name(h,args,n++);
ret=grib_get_double(h,key,&lon_first);
if (ret) return ret;
key = (char*)grib_arguments_get_name(h,args,n++);
ret=grib_get_double(h,key,&lat_last);
if (ret) return ret;
key = (char*)grib_arguments_get_name(h,args,n++);
ret=grib_get_double(h,key,&lon_last);
if (ret) return ret;
key = (char*)grib_arguments_get_name(h,args,n++);
ret=grib_get_long(h,key,&order);
if (ret) return ret;
key = (char*)grib_arguments_get_name(h,args,n++);
ret=grib_get_size(h,key,&self->nlats);
if (ret) return ret;
pl=(long*)grib_context_malloc(h->context,self->nlats*sizeof(long));
ret=grib_get_long_array(h,key,pl,&self->nlats);
if (ret) return ret;
lats=(double*)grib_context_malloc(h->context,sizeof(double)*order*2);
if((ret = grib_get_gaussian_latitudes(order, lats)) != GRIB_SUCCESS)
return ret;
if (self->nlats==order*2) {
/*global (latitudes)*/
self->lats=lats;
} else {
/*sub area (latitudes)*/
int l=0;
double d=fabs(lats[0]-lats[1]);
while (fabs(lat_first-lats[l]) > d ) {l++;}
self->lats=(double*)grib_context_malloc(h->context,sizeof(double)*self->nlats);
for (i=0;i<self->nlats;i++) self->lats[i]=lats[l++];
grib_context_free(box->context,lats);
}
self->lons=(double**)grib_context_malloc_clear(box->context,sizeof(double*)*self->nlats);
self->size=0;
if (lon_first != 0 ||
fabs(lon_last - (360.0-90.0/order)) > 90.0/order) {
/* sub area (longitudes) */
for (j=0;j<self->nlats;j++) {
row_count=0;
grib_get_reduced_row(pl[j],lon_first,lon_last,
&row_count,&ilon_first,&ilon_last);
self->size+=row_count;
if (ilon_first>ilon_last) ilon_first-=pl[j];
l=0;
self->lons[j]=(double*)grib_context_malloc_clear(c,sizeof(double)*row_count);
for (i=ilon_first;i<=ilon_last;i++)
self->lons[j][l++]=((i)*360.0)/pl[j];
pl[j]=row_count;
}
} else {
/* global (longitudes) */
for (j=0;j<self->nlats;j++) {
self->lons[j]=(double*)grib_context_malloc_clear(c,sizeof(double)*pl[j]);
self->size+=pl[j];
for (i=0;i<pl[j];i++)
self->lons[j][i]=(i*360.0)/pl[j];
}
}
self->nlons=pl;
return 0;
}
static int destroy(grib_box* box) {
grib_box_reduced_gaussian* self=(grib_box_reduced_gaussian*)box;
grib_context* c=box->context;
int i;
grib_points_delete(box->points);
grib_context_free(c,self->lats);
for (i=0;i<self->nlats;i++)
grib_context_free(c,self->lons[i]);
grib_context_free(c,self->lons);
return GRIB_SUCCESS;
}
static grib_points* get_points(grib_box* box, double north, double west, double south,double east, int *err) {
long j,i,index,l;
double lat,lon;
size_t group_count;
int first=1;
grib_box_reduced_gaussian* self=(grib_box_reduced_gaussian*)box;
grib_points* points=NULL;
grib_context* c=box->context;
points=grib_points_new(c,self->size);
if (!points)
grib_context_log(c,GRIB_LOG_FATAL,"unable to create grib_points\n");
index=0;
l=0;
group_count=0;
for (j=0;j<self->nlats;j++) {
lat=self->lats[j];
for (i=0;i<self->nlons[j];i++) {
lon=self->lons[j][i];
if (lat<north && lat>south && lon>west && lon<east) {
points->latitudes[l]=lat;
points->longitudes[l]=lon;
points->indexes[l]=index;
points->group_len[group_count]++;
if (first) {
points->group_start[group_count]=index;
points->group_len[group_count]=0;
first=0;
} else {
if (index!=points->group_start[group_count]+points->group_len[group_count]) {
group_count++;
points->group_start[group_count]=index;
points->group_len[group_count]=0;
points->n_groups=group_count+1;
}
}
l++;
}
index++;
}
}
points->group_len[group_count]++;
points->n=l;
if (box->points) grib_points_delete(box->points);
box->points=points;
*err=0;
return points;
}