/** * Copyright 2005-2007 ECMWF * * Licensed under the GNU Lesser General Public License which * incorporates the terms and conditions of version 3 of the GNU * General Public License. * See LICENSE and gpl-3.0.txt for details. */ /* * * Author: Enrico Fucile * * */ #include "grib_api_internal.h" /* This is used by make_class.pl START_CLASS_DEF CLASS = nearest SUPER = grib_nearest_class_gen IMPLEMENTS = init IMPLEMENTS = find;destroy MEMBERS = const char* J MEMBERS = const char* K MEMBERS = const char* M 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 "nearest.class" and rerun ./make_class.pl */ static void init_class (grib_nearest_class*); static int init (grib_nearest* nearest,grib_handle* h,grib_arguments* args); static int find(grib_nearest* nearest, grib_handle* h,double inlat, double inlon, unsigned long flags, double* outlats,double* outlons, double *values,double *distances, int *indexes,size_t *len); static int destroy (grib_nearest* nearest); typedef struct grib_nearest_sh{ grib_nearest nearest; /* Members defined in gen */ const char* values_key; const char* radius; int cargs; /* Members defined in sh */ const char* J; const char* K; const char* M; } grib_nearest_sh; extern grib_nearest_class* grib_nearest_class_gen; static grib_nearest_class _grib_nearest_class_sh = { &grib_nearest_class_gen, /* super */ "sh", /* name */ sizeof(grib_nearest_sh), /* size of instance */ 0, /* inited */ &init_class, /* init_class */ &init, /* constructor */ &destroy, /* destructor */ &find, /* find nearest */ }; grib_nearest_class* grib_nearest_class_sh = &_grib_nearest_class_sh; static void init_class(grib_nearest_class* c) { } /* END_CLASS_IMP */ #define LEGENDRE_SIZE(L) (L+1)*(L+2)/2 static void grib_trigs(int m,double lambda,double* c,double* s); static void grib_invtrans_legendre(int L,double x, double* RI,double* TR,double* TI); static double grib_invtrans_trig(int L,double* TR,double* TI, double *c,double *s); static double grib_invtrans(grib_context *c,int L,double latdeg,double londeg,double* values); static int init(grib_nearest* nearest,grib_handle* h,grib_arguments* args) { grib_nearest_sh* self = (grib_nearest_sh*) nearest; self->J = grib_arguments_get_name(h,args,self->cargs++); self->K = grib_arguments_get_name(h,args,self->cargs++); self->M = grib_arguments_get_name(h,args,self->cargs++); return 0; } static int find(grib_nearest* nearest, grib_handle* h, double inlat, double inlon,unsigned long flags, double* outlats,double* outlons, double *outvalues,double *distances,int* indexes, size_t *len) { grib_nearest_sh* self = (grib_nearest_sh*) nearest; long J,K,M; double *values; int size,i,ret; size_t vsize=0; double val; if( (ret = grib_get_long(h,self->J,&J))!= GRIB_SUCCESS) return ret; if( (ret = grib_get_long(h,self->K,&K))!= GRIB_SUCCESS) return ret; if( (ret = grib_get_long(h,self->M,&M))!= GRIB_SUCCESS) return ret; size=2*LEGENDRE_SIZE(J); vsize=size; values=(double*)grib_context_malloc_clear(h->context,sizeof(double)*size); if (!values) { grib_context_log(h->context,GRIB_LOG_ERROR, "nearest_sh: unable to allocate %d bytes", sizeof(double)*size); return GRIB_OUT_OF_MEMORY; } if( (ret = grib_get_double_array(h,self->values_key,values,&vsize)) != GRIB_SUCCESS) return ret; Assert(vsize==size); val=grib_invtrans(h->context,J,inlat,inlon,values); grib_context_free(h->context,values); for (i=0;i<4;i++) { outlats[i]=inlat; outlons[i]=inlon; outvalues[i]=val; indexes[i]=-1; } return GRIB_SUCCESS; } static int destroy(grib_nearest* nearest) { return GRIB_SUCCESS; } static void grib_trigs(int m,double lambda,double* c,double* s) { int i; double a,b; b=sin(lambda); a=1-2*sin(lambda/2.0)*sin(lambda/2.0); c[0]=1.0; s[0]=0.0; for (i=1;i<=m;i++) { c[i]=a*c[i-1]-b*s[i-1]; s[i]=a*s[i-1]+b*c[i-1]; } } static double grib_invtrans_trig(int L,double* TR,double* TI,double *c,double *s) { double ret=0; int m=0; for (m=1;m<=L;m++) { ret+= TR[m] * c[m]; printf("++ %d ++ %.20e %g %g\n",m,ret,TR[m],c[m]); ret-= TI[m] * s[m]; printf("+- %d ++ %.20e %g %g\n",m,ret,TI[m],s[m]); } ret=2*ret+TR[0]; return ret; } static void grib_invtrans_legendre(int L,double x, double* RI,double* TR,double* TI) { int l,m; double y2; double f,of,fx,p0; double *pP,*oP,*pRI; if (abs(x) > 1.0) { printf("grib_legendreP: invalid x=%g must be abs(x)>0\n",x); exit(1); } if (L<0) { printf("grib_legendreP: invalid L=%d must be >0\n",L); exit(1); } pP=(double*)malloc(sizeof(double)*(L+1)); if (!pP) { printf("unable to allocate %d bytes\n",(int)sizeof(double)*(L+1)); exit(1); } y2=(1.0-x*x); fx=1; p0=1; oP=pP; pRI=RI; for (m=0;m