mirror of https://github.com/ecmwf/eccodes.git
293 lines
8.3 KiB
C
293 lines
8.3 KiB
C
/*
|
|
* Copyright 2005-2019 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 = 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 int 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 int grib_invtrans(grib_context *c,int L,double latdeg,double londeg,double* values, double* result);
|
|
|
|
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);
|
|
|
|
ret=grib_invtrans(h->context,J,inlat,inlon,values, &val);
|
|
if (ret != GRIB_SUCCESS) return ret;
|
|
|
|
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 int 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 (fabs(x) > 1.0) {
|
|
printf("grib_legendreP: invalid x=%g must be abs(x)>0\n",x);
|
|
return GRIB_INVALID_ARGUMENT;
|
|
}
|
|
if (L<0) {
|
|
printf("grib_legendreP: invalid L=%d must be >0\n",L);
|
|
return GRIB_INVALID_ARGUMENT;
|
|
}
|
|
|
|
pP=(double*)malloc(sizeof(double)*(L+1));
|
|
if (!pP) {
|
|
printf("unable to allocate %d bytes\n",(int)sizeof(double)*(L+1));
|
|
return GRIB_OUT_OF_MEMORY;
|
|
}
|
|
|
|
y2=(1.0-x*x); fx=1; p0=1; oP=pP; pRI=RI;
|
|
for (m=0;m<L;m++) {
|
|
/* printf("\n"); */
|
|
pP[0]=sqrt((2*m+1)*p0);
|
|
if (m & 1) pP[0]=-pP[0];
|
|
TR[m]=pP[0] * *(pRI++);
|
|
TI[m]=pP[0] * *(pRI++);
|
|
printf("-- (%d,%d) %.20e %.20e\n",m,m,TR[m],pP[0]);
|
|
of=sqrt(2*m+3);
|
|
pP[1]=x*of*pP[0];
|
|
TR[m]+=pP[1] * *(pRI++);
|
|
TI[m]+=pP[1] * *(pRI++);
|
|
printf("-- (%d,%d) %.20e %.20e\n",m+1,m,TR[m],pP[1]);
|
|
for (l=m+2;l<=L;l++) {
|
|
f=sqrt((4.0*l*l-1.0)/(l*l-m*m));
|
|
pP[2]=(x*pP[1]-pP[0]/of)*f;
|
|
TR[m]+=pP[2] * *(pRI++);
|
|
TI[m]+=pP[2] * *(pRI++);
|
|
printf("-- (%d,%d) %.20e %.20e\n",l,m,TR[m],pP[2]);
|
|
of=f;
|
|
pP++;
|
|
}
|
|
pP=oP;
|
|
p0*=y2*fx/(fx+1.0);
|
|
fx+=2;
|
|
}
|
|
/* printf("\n"); */
|
|
pP[0]=sqrt((2*L+1)*p0);
|
|
if (L & 1) pP[0]=-pP[0];
|
|
TR[L]=pP[0] * *(pRI++);
|
|
TI[L]=pP[0] * *(pRI++);
|
|
printf("-- (%d,%d) %.20e %.20e\n",L,L,TR[m],pP[0]);
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
static int grib_invtrans(grib_context* context, int L, double latdeg, double londeg, double* values,
|
|
double* result)
|
|
{
|
|
double *c,*s,*TR,*TI;
|
|
double sinlat,deg2rad,lonrad;
|
|
int Lp1=L+1;
|
|
int err = 0;
|
|
|
|
deg2rad=acos(0.0)/90.0;
|
|
sinlat=sin(latdeg*deg2rad);
|
|
lonrad=londeg*deg2rad;
|
|
|
|
c=(double*)grib_context_malloc_clear(context,sizeof(double)*Lp1);
|
|
if (!c) {
|
|
grib_context_log(context,GRIB_LOG_ERROR,
|
|
"nearest_sh: unable to allocate %d bytes",sizeof(double)*Lp1);
|
|
return GRIB_OUT_OF_MEMORY;
|
|
}
|
|
|
|
s=(double*)grib_context_malloc_clear(context,sizeof(double)*Lp1);
|
|
if (!s) {
|
|
grib_context_log(context,GRIB_LOG_ERROR,
|
|
"nearest_sh: unable to allocate %d bytes",sizeof(double)*Lp1);
|
|
return GRIB_OUT_OF_MEMORY;
|
|
}
|
|
|
|
grib_trigs(L,lonrad,c,s);
|
|
|
|
TR=(double*)grib_context_malloc_clear(context,sizeof(double)*Lp1);
|
|
if (!TR) {
|
|
grib_context_log(context,GRIB_LOG_ERROR,
|
|
"nearest_sh: unable to allocate %d bytes",sizeof(double)*Lp1);
|
|
return GRIB_OUT_OF_MEMORY;
|
|
}
|
|
TI=(double*)grib_context_malloc_clear(context,sizeof(double)*Lp1);
|
|
if (!TI) {
|
|
grib_context_log(context,GRIB_LOG_ERROR,
|
|
"nearest_sh: unable to allocate %d bytes",sizeof(double)*Lp1);
|
|
return GRIB_OUT_OF_MEMORY;
|
|
}
|
|
|
|
err = grib_invtrans_legendre(L,sinlat,values,TR,TI);
|
|
if(err) return err;
|
|
|
|
*result=grib_invtrans_trig(L,TR,TI,c,s);
|
|
|
|
grib_context_free(context,c);
|
|
grib_context_free(context,s);
|
|
grib_context_free(context,TR);
|
|
grib_context_free(context,TI);
|
|
|
|
return GRIB_SUCCESS;
|
|
}
|